ডাউনকাস্টিং শেয়ারড_প্টার <বেস> শেয়ারড_প্টরে <ডেরাইভড>?


103

আপডেট: এই উদাহরণে ভাগ করা_পটারটি বুস্টের মতো, তবে এটি শেয়ারড_পলিমারফিক_ডাউন কাস্ট (বা সেই ক্ষেত্রে ডায়নামিক_পয়েন্টার_কাস্ট বা স্ট্যাটিক_পয়েন্টার_কাস্ট) সমর্থন করে না!

আমি রেফারেন্স গণনাটি না হারিয়ে একটি উত্পন্ন শ্রেণিতে একটি ভাগ করা পয়েন্টার শুরু করার চেষ্টা করছি:

struct Base { };
struct Derived : public Base { };
shared_ptr<Base> base(new Base());
shared_ptr<Derived> derived;

// error: invalid conversion from 'Base* const' to 'Derived*'
derived = base;  

এ পর্যন্ত সব ঠিকই. আমি আশা করিনি যে সি ++ বেইসটিকে স্পষ্টতই বেস * কে ডেরিভড * এ রূপান্তর করবে। যাইহোক, আমি কোডটির দ্বারা প্রকাশিত কার্যকারিতাটি চাই (এটি হল বেস পয়েন্টারটি ডাউনকাষ্ট করার সময় রেফারেন্স গণনা বজায় রাখা)। আমার প্রথম চিন্তাটি বেসে একটি কাস্ট অপারেটর সরবরাহ করা ছিল যাতে ডেরিভডের একটি অন্তর্নিহিত রূপান্তর ঘটতে পারে (প্যাডেন্টদের জন্য: আমি পরীক্ষা করব যে ডাউন কাস্টটি বৈধ কিনা, চিন্তা করবেন না):

struct Base {
  operator Derived* ();
}
// ...
Base::operator Derived* () {
  return down_cast<Derived*>(this);
}

ঠিক আছে, এটি কোনও লাভ হয়নি। দেখে মনে হচ্ছে সংকলকটি আমার টাইপকাস্ট অপারেটরটিকে সম্পূর্ণ উপেক্ষা করেছে। কীভাবে কোনও ধারণাগুলি কীভাবে আমি ভাগ করে নেওয়া_এসপিআর্টমেন্ট কাজ করতে পারি? অতিরিক্ত পয়েন্টগুলির জন্য: কী ধরণের Base* const? const Base*বুঝলাম, তবে Base* const? এক্ষেত্রে কী বোঝায় const?


আপনার কেন ভাগ করা_পিটার <ব্যাস> পরিবর্তে একটি শেয়ারড_পিটার <ডেরাইভড> প্রয়োজন?
বিল

4
কারণ আমি অবজেক্টটির ক্লোনিং না করে ব্যাসে নেই এমন ডেরিভডে কার্যকারিতা অ্যাক্সেস করতে চাই (আমি দুটি ভাগ করে নেওয়া পয়েন্টার দ্বারা রেফারেন্সযুক্ত একটি একক বস্তু চাই)। যাইহোক, কাস্ট অপারেটররা কেন কাজ করে না?
লাজোস নাগি

উত্তর:


112

আপনি ব্যবহার করতে পারেন dynamic_pointer_cast। এটি দ্বারা সমর্থিত std::shared_ptr

std::shared_ptr<Base> base (new Derived());
std::shared_ptr<Derived> derived =
               std::dynamic_pointer_cast<Derived> (base);

ডকুমেন্টেশন: https://en.cppreferences.com/w/cpp/memory/shared_ptr/pointer_cast

এছাড়াও, আমি বেস শ্রেণিতে কাস্ট অপারেটর ব্যবহার করার পরামর্শ দিই না। এর মতো অন্তর্নিহিত castালাই বাগ এবং ত্রুটির উত্স হতে পারে।

-উপডেট: টাইপটি বহুমুখী std::static_pointer_castনা হলে ব্যবহার করা যেতে পারে।


5
তিনি যে প্রথম লাইনটি ব্যবহার করছেন না তা থেকে বুঝতে পারিনি std::shared_ptr। তবে প্রথম উত্তরের মন্তব্য থেকে আমি অনুমান করেছিলাম যে তিনি বুস্ট ব্যবহার করছেন না, তাই তিনি সম্ভবত ব্যবহার করছেন std::shared_ptr
মাসউদ খারি

ঠিক আছে. দুঃখিত তার আরও ভালভাবে স্পষ্ট করা উচিত যে তিনি একটি কাস্টম বাস্তবায়ন ব্যবহার করছেন।
মাসউদ খারি

47

আমি ধরে নিচ্ছি আপনি ব্যবহার করছেন boost::shared_ptr... আমার মনে হয় আপনি চান dynamic_pointer_castবা shared_polymorphic_downcast

তবে এগুলির জন্য বহুবিধ প্রকারের প্রয়োজন।

কি ধরণের Base* const? const Base*বুঝলাম, তবে Base* const? এক্ষেত্রে কী বোঝায় const?

  • const Base *একটি ধ্রুবকের জন্য পরিবর্তনীয় পয়েন্টার Base
  • Base const *একটি ধ্রুবকের জন্য পরিবর্তনীয় পয়েন্টার Base
  • Base * constএকটি পরিবর্তনীয় স্থির পয়েন্টার Base
  • Base const * constএকটি ধ্রুবক একটি ধ্রুবক পয়েন্টার Base

এখানে একটি ন্যূনতম উদাহরণ:

struct Base { virtual ~Base() { } };   // dynamic casts require polymorphic types
struct Derived : public Base { };

boost::shared_ptr<Base> base(new Base());
boost::shared_ptr<Derived> derived;
derived = boost::static_pointer_cast<Derived>(base);
derived = boost::dynamic_pointer_cast<Derived>(base);
derived = boost::shared_polymorphic_downcast<Derived>(base);

আমি নিশ্চিত নই যে এটি ইচ্ছাকৃত ছিল কিনা যে আপনার উদাহরণটি বেস টাইপের একটি উদাহরণ তৈরি করে এবং এটি কাস্ট করে, তবে এটি পার্থক্যটি সুন্দরভাবে ফুটিয়ে তুলেছে।

static_pointer_castইচ্ছা "শুধু এটা করতে"। এটি অনির্ধারিত আচরণের ফলে ঘটবে ( Derived*মেমরির জন্য বরাদ্দ হওয়া এবং এটি দ্বারা সূচনা করা Base) এবং সম্ভবত ক্রাশ বা আরও খারাপ হতে পারে। উপর রেফারেন্স গণনা baseবৃদ্ধি করা হবে।

dynamic_pointer_castএকটি নাল পয়েন্টার স্থাপিত হবে। উপর রেফারেন্স গণনা baseঅপরিবর্তিত হবে।

shared_polymorphic_downcastএকটি স্ট্যাটিক ঢালাই যেমন একই ফলাফল হবে, বরং সফল হতে ভান এবং অনির্ধারিত আচরণ নেতৃস্থানীয় চেয়ে একটি বিবৃতি আরম্ভ হবে। উপর রেফারেন্স গণনা baseবৃদ্ধি করা হবে।

দেখুন (মৃত লিঙ্ক) :

কখনও কখনও এটি কিনা ব্যবহার করার সিদ্ধান্ত নেন একটু কঠিন static_castবা dynamic_cast, এবং আপনি ইচ্ছা উভয় বোথ ওয়ার্ল্ডস একটি সামান্য বিট ফেলতে পারে। এটি সর্বজনবিদিত যে ডাইনামিক_কাস্টের একটি রানটাইম ওভারহেড থাকে তবে এটি নিরাপদ, যেখানে স্ট্যাটিক_কাস্টের কোনও ওভারহেড থাকে না তবে এটি নিঃশব্দে ব্যর্থ হতে পারে। আপনি যদি shared_dynamic_castডিবাগ বিল্ডগুলি, এবং shared_static_castরিলিজ বিল্ডগুলিতে ব্যবহার করতে পারতেন তবে এটি কতই না সুন্দর । ঠিক আছে, এই জাতীয় জিনিস ইতিমধ্যে উপলব্ধ এবং বলা হয় shared_polymorphic_downcast


দুর্ভাগ্যক্রমে, আপনার সমাধান বুস্ট কার্যকারিতার উপর নির্ভর করে যা আমরা ব্যবহার করছি সেই বিশেষ ভাগ করা_পিত্তিক বাস্তবায়ন থেকে ইচ্ছাকৃতভাবে বাদ দেওয়া হয়েছিল (কেন জিজ্ঞাসা করবেন না)। কনস্টের ব্যাখ্যা হিসাবে, এটি এখন আরও বেশি অর্থবোধ করে।
লাজোস নাগি

4
অন্যান্য নির্মাতা বাস্তবায়নের সংক্ষিপ্ততা shared_ptr(গ্রহণ static_cast_tagএবং dynamic_cast_tag), আপনার করার মতো খুব বেশি কিছু নেই। আপনি বাইরে যা কিছু করেন shared_ptrতা পুনরায় হিসাব পরিচালনা করতে সক্ষম হবে না। - একটি "নিখুঁত" ওও ডিজাইনে আপনি সর্বদা বেস প্রকারটি ব্যবহার করতে পারেন এবং উত্পন্ন ধরণটি কী তা জানা বা যত্নের প্রয়োজন নেই কারণ এর সমস্ত কার্যকারিতা বেস-ক্লাস ইন্টারফেসের মাধ্যমে উদ্ভাসিত হয়। সম্ভবত আপনাকে প্রথমে পুনরায় চিন্তা করতে হবে কেন আপনাকে প্রথমে ডাউন কাস্ট করতে হবে।
টিম সিলভেস্টার

4
@ টিম সিলভেস্টার: তবে, সি ++ একটি "নিখুঁত" ওও ভাষা নয়! :-) ডাউন-ক্যাসেটগুলির একটি নিখুঁত ওও ভাষায় তাদের স্থান রয়েছে
স্টিভ ফলি

5

যদি কেউ এখানে পদোন্নতি নিয়ে আসে তবে: শেয়ার করা_পিটার ...

এইভাবে আপনি উত্সাহিত বুস্ট শেয়ার্ড_প্টারে ডাউনকাস্ট করতে পারেন। বেস থেকে প্রাপ্ত উত্তরাধিকারসূত্রে ধরে নেওয়া।

boost::shared_ptr<Base> bS;
bS.reset(new Derived());

boost::shared_ptr<Derived> dS = boost::dynamic_pointer_cast<Derived,Base>(bS);
std::cout << "DerivedSPtr  is: " << std::boolalpha << (dS.get() != 0) << std::endl;

নিশ্চিত করুন যে 'বেস' শ্রেণি / কাঠামোর কমপক্ষে একটি ভার্চুয়াল ফাংশন রয়েছে। ভার্চুয়াল ডেস্ট্রাক্টরও কাজ করে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.