سؤال

لدي مجموعة من كائنات الطالب المخصصة.يرث كل من CourseStudent وResearchStudent من Student، وجميع مثيلات Student هي واحدة أو أخرى من هاتين المثيلتين.

لدي وظيفة لتصفح المصفوفة، وتحديد النوع الفرعي لكل طالب، ثم استدعاء وظائف الأعضاء الخاصة بالنوع الفرعي عليها.

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

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

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

المحلول

تحتاج إلى طاقم ديناميكي:

Student * s = new ...;    // create student of some sort

if ( ResearchStudent * r = dynamic_cast<ReasearchStudent*>( s ) ) {
   r->ResFunc();
}
else if ( CourseStudent * c = dynamic_cast<CourseStudent*>( s ) ) {
   c->CourseFiunc();
}
else {
   throw "unknown student type";
}

لاحظ أن هذا يستخدم معلومات النوع التي يحتفظ بها المترجم ، شريطة أن يكون للفئة وظيفة افتراضية واحدة على الأقل - إذا فشل كل شيء آخر ، اجعل Destructor افتراضيًا (كما يجب أن يكون في هذه الحالة). يجب أن تفضل دائمًا هذا النهج للحفاظ على معلومات النوع الخاصة بك.

نصائح أخرى

أفضل شيء هو استخدام الوظائف الافتراضية:

class Student
{
   // ...
   virtual void SpecificFunction() = 0; /* = 0 means it's abstract; it must be implemented by a subclass */
   // ...
};

class CourseStudent
{
    void SpecificFunction() { ... }
};

ثم يمكنك القيام بما يلي:

Student *student;
student->SpecificFunction();

يمكن أن يكون البديل (الأسوأ) هو الاستخدام dynamic_cast:

Student *student;
CourseStudent *cs = dynamic_cast<CourseStudent *>(student);

if (cs) {
   /* student is a CourseStudent.. */
   cs->SpecificFunction();
}

الوظائف الافتراضية غير مناسبة هنا لأن وظائف أعضاء الفئة الفرعية خاصة بتلك الفئات الفرعية (على سبيل المثال ، يحتوي Coursestudent على قائمة بالوحدات ، في حين أن البحث عن البحث لا يعني ذلك ، لذلك لن يكون تنفيذ وظيفة getUnits () في Researchstudent لا معنى له على الإطلاق)

كان لدي القليل من القراءة على قوالب ديناميكية وثابتة ( cplusplus.com typecasting ) ، وفي هذه الحالة أعتقد أن الممثلين الثابتين أكثر ملاءمة.

العيب العام لـ static_cast هو أنه لا يؤدي أي فحص في وقت التشغيل للتأكد من أن الكائن الذي يتم إلقاؤه إلى نوع فرعي هو في الواقع هذا النوع الفرعي وليس بعضًا آخر. في هذه الحالة ، أتحقق بشكل خاص من النوع قبل أن أقوم بتنفيذ النوع (باستخدام عضو خاص للبيانات يتم تعيينه في مُنشئ الفئة الفرعية وليس لديه موطف) ، طالما أن فحص بلدي جيد ، لا ينبغي أن تكون هناك مشكلة في طاقم ثابت . يعد فريق العمل الثابت أكثر كفاءة نظرًا لأن فريق العمل الديناميكي يتطلب المزيد من موارد وقت التشغيل لأداء فحص النوع.

في حالة عدم وجود أي فرصة لعدم كونه من النوع المتوقع ، لن يكون الصب الثابت مناسبًا ، لذا سأذهب إلى الصب الديناميكي (هذه مهمة ، لذا بمجرد تقديمها ، لن يلزم الحفاظ على الرمز ، لذلك هناك لا خطر على شخص ما العبث في وقت لاحق).

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

انت تحتاج static_cast من أجل هذا. نظرًا لأن هذه الوظائف ليست أعضاء افتراضيين في الفئة الأساسية ، لا يمكنك الاتصال بهم من خلال مؤشر من فئة المؤشر إلى القاعدة. تحتاج إلى الإلقاء بشكل صريح للنوع الفعلي للكائن.

عادةً ما يتم حل هذه المشكلة بشكل أفضل مع وظائف افتراضية - لن تحتاج إلى فحص نوع الكائن في الكود الخاص بك بعد الآن ، سيكون لديه رمز أقل وأقل السطح للأخطاء.

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