سؤال

أريد تخزين كائن من بعض الفصول المشتقة كخاصية لكائن آخر.

المشكلة بالنسبة لي هي معرفة حجم الكائن الذي سيتم تخزينه ، حيث يمكن أن يكون أي فئة مشتقة من فئة قاعدة معينة. لا يمكنني فقط تخصيص الذاكرة لكائن الفئة الأساسية ، بشكل صحيح ، لأنه أصغر. أفترض، نوع من المشغل سوف يعطي فقط حجم الفئة الأساسية ، أليس كذلك؟

هنا هو رمز العينة الخاص بي. من فضلك ، انظر التعليقات لفهم ما أعنيه. المعذرة على عدم الدعامة ...

BaseA {};

DerivedA1 : BaseA {public: void property() { cout << 1; }};
DerivedA2 : BaseA {public: void property() { cout << 2; }};
// etc. - several derived classes.

BaseB   // Contains (or links to) an instance of class derived from BaseA.
{
public:
    BaseA * instanceA;

    BaseB (BaseA instanceAX)
    {
        // ??? => How to allocate memory for the object
        // I don't know the real type of?
        instanceA = new BaseA (instanceAX);
    }

    BaseB (BaseA instanceAX) { delete instanceA; }
};

main()
{
    DerivedA1 instanceA1;
    BaseB instanceB (instanceA1);

    // Use "property" regardless of which derived class it belongs to.
    instanceB.instanceA->property();
} 

يمكنني تخزين مؤشر بدلاً من الكائن نفسه ، سيكون أسهل. لكنني لست متأكدًا من أنني أرغب في الاعتماد على المتصل للاحتفاظ بكائن الملكية لحياة المثال مثيل ب.

شكرًا!

هل كانت مفيدة؟

المحلول

حسنًا ، أولاً وقبل كل شيء ، نظرًا لأنك تمر في BASEEA حسب القيمة ، وليس بالرجوع إليها أو المؤشر ، فأنت تعرف النوع ؛ إنه باسا. تم نسخ Bostb إلى قاع ويتم إرسال نسخة BASEA إلى الوظيفة. لا يوجد أي بيانات إضافية في BASEB في Instanceax. وهذا ما يسمى "التقطيع".

ولكن ، للإجابة على سؤالك ، أنت ببساطة لا تفعل ذلك بهذه الطريقة. تحتاج إلى وظيفة clone () في فئة baseb الخاصة بك إذا كان من المفترض أن تعمل بهذه الطريقة. بدلاً من ذلك ، يمكنك تصميم مؤشر ذكي أو كائن آخر يمكنه استنساخ المثيل لك. إذا بحثت عن اسمي على comp.lang.c ++ جنبا إلى جنب مع clone () ، فقد تصادف مناقشة لدي حول هذه الفكرة الأخيرة.

وظيفة الاستنساخ هي بالطبع وظيفة افتراضية تُرجع نسخة من الكائن الحالي:

struct BaseA
{
  virtual BaseA* clone() const = 0;
};

struct BaseB : BaseA
{
  BaseB* clone() const { return new BaseB(*this); }
};

نصائح أخرى

أرى احتمالين.

  • يعطي BaseA وظيفة عضو افتراضية بحتة ، ربما تسمى clone, ، هذا مسؤول عن إنشاء نسخة من المثيل. ثم مُنشئ BaseB يمكن أن تصبح

    BaseB (BaseA const &instanceAX) { instanceA = instanceAX.clone (); }

  • يمكنك أيضًا تجنب تمرير المؤشرات الخام حولها واستخدامها boost::shared_ptr في حين أن. وبهذه الطريقة ، نظرًا لأنه مرجعي ، لا يمكن أن يتسبب المتصل في تدمير سابق لأوانه BaseA الاشتقاق الذي تم استخدامه للبناء BaseB. يجب عليك ضبط BaseA * instanceA; ليقرأ boost::shared_ptr <BaseA> instanceA; ثم BaseBقد يبدو مُنشئه:

    BaseB (boost::shared_ptr <BaseA> a) : instanceA (a) { }

مشكلة APCTH الأولى هي أن بعض مبرمج العميل الذي يرث منه ، على سبيل المثال DerivedA1 قد تنسى التنفيذ clone في اشتقاقه. إن المشكلة الرئيسية لـ APCTH الثانية هي مطالبة كل مستخدم BaseB لتخصيص كائن العقار على الكومة (بما أنك تقوم بنسخة في الداخل BaseBمُنشئ S على أي حال ، على الأقل لن يرتفع استهلاك الذاكرة ، رغم ذلك)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top