سؤال

لدي ثلاث مختلف فئات أساسية:

class BaseA
{
public:
    virtual int foo() = 0;
};

class BaseB
{
public:
    virtual int foo() { return 42; }
};

class BaseC
{
public:
    int foo() { return 42; }
};

ثم تستمد من قاعدة مثل هذا (استبدال X A, B أو C):

class Child : public BaseX
{
public:
    int foo() { return 42; }
};

كيف هي وظيفة تجاوز في ثلاثة مختلفة قاعدة الطبقات ؟ هي ثلاثة الافتراضات التالية صحيحة ؟ هل هناك أي محاذير أخرى?

  • مع BaseA الطفل فئة لا تجمع ، ظاهرية خالصة وظيفة ليست محددة.
  • مع BaseB الدالة في الطفل يسمى عند استدعاء فو على BaseB* أو الطفل*.
  • مع BaseC الدالة في الطفل يسمى عند استدعاء فو على الطفل* ولكن ليس على BaseB* (وظيفة في الفئة الأصل ويسمى).
هل كانت مفيدة؟

المحلول

في الفئة المشتقة، تكون الطريقة افتراضية إذا تم تعريفها افتراضية في الفئة الأساسية، حتى لو لم يتم استخدام الكلمة الأساسية الافتراضية في طريقة الفئة المشتقة.

  • مع BaseA, ، سيتم تجميعه وتنفيذه على النحو المنشود foo() كونها افتراضية وتنفيذية في الفصل Child.
  • نفس الشيء مع BaseB, ، سيتم أيضًا تجميعه وتنفيذه على النحو المنشود باستخدام foo() يجري الظاهري () والتنفيذ في الفصل Child.
  • مع BaseC ومع ذلك، فإنه سيتم تجميع وتنفيذ، ولكن سيتم تنفيذ BaseC الإصدار إذا كنت تسميه من سياق BaseC, ، و ال Child الإصدار إذا اتصلت بسياق Child.

نصائح أخرى

القاعدة المهمة التي يجب تذكرها هي أنه بمجرد الإعلان عن دالة افتراضية، تكون الوظائف ذات التوقيعات المتطابقة في الفئات المشتقة افتراضية دائمًا.لذلك، تم تجاوزه بالنسبة لـ Child of A وChild of B، اللذين سيتصرفان بشكل مماثل (باستثناء أنك لا تستطيع إنشاء BaseA مباشرة).

ومع ذلك، مع لغة C، لا يتم تجاوز الوظيفة، بل يتم تحميلها بشكل زائد.في هذه الحالة، فقط النوع الثابت هو المهم:سوف يطلق عليه ما هو مؤشر عليه (النوع الثابت) بدلاً من ما هو الكائن بالفعل (النوع الديناميكي)

مع BaseA الطفل فئة لا ترجمة نقية الظاهري وظيفة لم يتم تعريفها

هذا صحيح فقط إذا كنت في محاولة إنشاء كائن من BaseA.إذا قمت بإنشاء كائن من الطفل ومن ثم يمكنك الاتصال فو() باستخدام إما BaseA* أو الطفل*

مع BaseB الدالة في الطفل ويسمى عند استدعاء فو على BaseB* أو الطفل*.

يعتمد على نوع الكائن ككائن يمكن أن تكون إما BaseB أو الطفل.إذا كان الكائن هو BaseB ثم BaseB::فو يسمى.

مع BaseC, thefunction في الطفل ويسمى عند استدعاء فو على الطفل* ولكن ليس على BaseB* (وظيفة في الفئة الأصل ويسمى).

نعم, ولكنك لا تريد أن تفعل هذا.

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

يعتمد الأمر في الغالب على كيفية تسميته.

اذا فعلت:

class Child : public BaseA
{
public:
    int foo() { return 42; }
};

و فعل

BaseA baseA = new Child();
baseA->foo();

سوف يستدعي وظيفة Child's foo.

ومع ذلك، إذا فعلت هذا:

BaseA baseA = new BaseA();

من شأنه أن ينتج خطأ وقت الترجمة.

طفل الصف سوف ترجمة إذا كانت مشتقة من A، فلا يمكنك إنشاء كائنات من هذا النوع.

قد يكون هذا مفيدًا إذا كنت تريد تجاوز بعض الوظائف من Base، ثم اشتقاقها مرة أخرى.

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