سؤال

هذا السؤال سبق الجواب هنا:

بالنظر إلى المثال التالي, لماذا يجب أن تستخدم صراحة البيان b->A::DoSomething() بدلا من مجرد b->DoSomething()?

لا ينبغي أن المترجم هو الزائد القرار معرفة الأسلوب الذي أتحدث عنه ؟

أنا باستخدام Microsoft VS 2005.(ملاحظة:باستخدام الظاهري لا يساعد في هذه الحالة.)

class A
{
  public:
    int DoSomething() {return 0;};
};

class B : public A
{
  public:
    int DoSomething(int x) {return 1;};
};

int main()
{
  B* b = new B();
  b->A::DoSomething();    //Why this?
  //b->DoSomething();    //Why not this? (Gives compiler error.)
  delete b;
  return 0;
}
هل كانت مفيدة؟

المحلول

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

سيكون أحد الحلول سحب الزائد من A في B's نطاق:

class B : public A {
public:
    using A::DoSomething;
    // …
}

نصائح أخرى

الزائد القرار هو واحد من أبشع أجزاء من C++

أساسا المترجم يجد اسم المباراة "DoSomething(الباحث)" في نطاق ب ، يرى المعلمات لا تتطابق ، وتوقف مع وجود خطأ.

ويمكن التغلب عليها عن طريق استخدام A::DoSomething في فئة ب

class A  
{  
  public:  
    int DoSomething() {return 0;}
};  

class B : public A  
{  
  public:  
    using A::DoSomething;
    int DoSomething(int x) {return 1;} 
};   


int main(int argc, char** argv)
{
  B* b = new B();  
  // b->A::DoSomething();    // still works, but...
  b->DoSomething();    // works now too
  delete b;  
  return 0;
}

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

للحصول على من حوله ، عليك أن تخبر المترجم الأسلوب الذي تريد الاتصال به عن طريق وضع باستخدام::DoSomething في الفئة ب.

انظر هذه المادة من أجل نظرة سريعة إلى هذا السلوك.

وجود طريقة في فئة مشتقة يخفي كل الأساليب مع نفس الاسم (بغض النظر عن المعلمات) في قاعدة الطبقات.ويتم ذلك لتجنب مشاكل من هذا القبيل:

class A {} ;
class B :public A
{
    void DoSomething(long) {...}
}

B b;
b.DoSomething(1);     // calls B::DoSomething((long)1));

في وقت لاحق من شخص التغييرات فئة A:

class A
{
    void DoSomething(int ) {...}
}

الآن فجأة:

B b;
b.DoSomething(1);     // calls A::DoSomething(1);

وبعبارة أخرى, إذا لم يعمل مثل هذا ، لا علاقة لها تغيير في فئة لا يمكنك التحكم (أ) يمكن أن بصمت تؤثر على كيفية الكود الخاص بك يعمل.

هذا له علاقة مع الطريقة اسم القرار يعمل.نحن في الأساس نجد أول نطاق من اسم يأتي ثم نقوم بجمع كل الزائدة عن هذا الاسم في هذا النطاق.ومع ذلك ، فإن نطاق في حالتك هي الفئة ب ، في الفئة ب ، ب::DoSomething يخفي A::DOSomething:

3.3.7 اسم يختبئ [الأساسي.نطاق.إخفاء]

...[قص]...

3 في وظيفة عضو التعريف إعلان الاسم المحلي يخفي إعلان عضو من الطبقة مع نفس الاسم ؛ انظر basic.scope.class.إعلان عضو في فئة مشتقة (فئة.المشتقة) يخفي إعلان عضوا في الفئة الأساسية من نفس الاسم ؛ انظر فئة.الأعضاء.البحث.

لأن من اسم يختبئ،:: DoSomething لا حتى النظر في القرار الزائد

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

يمكنك جعل قاعدة الطبقة وظيفة واضحة مع استخدام الإعلان:

class B : public A  
{  
  public:  
    int DoSomething(int x) {return 1;};  
    using A::DoSomething;
};  

هذا ليس الحمولة الزائدة!أن يختبئ!

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

class B : public A  
{  
  public:
    using A::DoSomething;
    int DoSomething(int x) {return 1;};  
}; 

وظيفة خفية من خلال وظيفة بنفس الاسم في الفئة الفرعية (لكن مع اختلاف في التوقيع).يمكنك إظهار ذلك باستخدام باستخدام البيان ، كما هو الحال في استخدام::DoSomething () ؛

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