هناك عدد غير قليل من الأشياء غير واضحة حول تصميمك ، ولكن إذا كان السؤال هو ما إذا كان يمكنك فرض هذا النوع T
في وظيفة العضو Templa Add
يمكن فرضها على الاشتقاق من BaseClass
, ، الخيارات بسيطة:
- لا تفعل شيئًا ، سيشتكي المترجم بكل سرور على الخط
BaseClass* baseClass = new T();
- أضف تأكيدًا ثابتًا لجعل هذا أكثر وضوحًا
- استخدم حيل Sfinae الفاخرة لإزالة الوظيفة من مجموعة الأحمال الزائدة
سأذهب لأي من أول اثنين. يمكن تهجئة التأكيد الثابت على النحو التالي:
static_assert(std::is_base_of<BaseClass,T>::value);
خدعة sfinae ، كنت أتجنب ذلك حقًا ، لأنها ستجعل الكود أكثر إرباكًا ، ولكن يمكن تنفيذها على النحو التالي:
template <class T>
typename std::enable_if<std::is_base_of<BaseClass,T>::value,T*>::type
Add() {
baseClasses.push_back(new T());
return baseClasses.back();
}
(لاحظ أنني غيرت نوع الإرجاع ليكون T*
, ، الكائن هو أ T
, ، لماذا تعود أ BaseClass*
؟ الأمر نفسه ينطبق على Get
وظيفة لا جدوى من إرجاع أ BaseClass*
, ، عندما تعلم أن الكائن هو حقا T
)
الآن أصبحت المشكلة الفعلية أكثر تعقيدًا ، لأن تصميمك يتجنب بنشاط اعتبارات الملكية ، وهو ما لا ينبغي عليك ذلك. فكر في ملكية الكائنات وتأكد من وجود مالك واضح (أو أن المورد مشترك). بمجرد معرفة من يملك الكائنات ، قم بإنشاء بروتوكول لبقية الكود لإخطار المالك عندما يحتاج كائن إلى حذفه. إذا سمحت أي رمز لحذف المؤشرات التي تحتفظ بها ، سوف تصادف سلوكًا غير محدد قريبًا.
يمكن أن تشمل المخاوف الأقل أقل حقيقة أنك تفرض أن جميع المكونات لديها مُنشئ افتراضي ، والذي قد يكون مناسبًا أو لا يكون ذلك. يمكنك تبسيط هذا التقييد من خلال وجود غير معروف Add
يتطلب ذلك مؤشرًا ، والسماح للمتصل بإنشاء الكائنات بالطريقة التي يحلو لها.
استخدام typeid
عادةً ما يكون رمزًا صغيرًا ولا أعتقد أن هذا هو الاستثناء ، فربما تكون أفضل حالًا من خلال تصميم التسلسل الهرمي الذي يمكنك أن تسأل عن الكائن ، بدلاً من الجري typeid
. إذا كنت مصممًا حقًا على إنشاء الواجهة بناءً على الأنواع ، ففكر فيما إذا كان dynamic_cast
يمكن ان يكون افضل. سيكون أكثر كفاءة ، ولكن إذا كان لديك مستويات متعددة من الميراث ، فسيتيح لك إرجاع الكائنات الأكثر اشتقاقًا ككائنات وسيطة