2010-06-29 3 views
4

Я учусь о полиморфизме, и я смущен этой ситуацией: Скажем, у меня есть следующие классы C++:Если переопределенная функция C++ вызывает родительскую функцию, которая вызывает другую виртуальную функцию, что называется?

class A{ 
    ... 
    virtual void Foo(){ 
     Boo(); 
    } 
    virtual void Boo(){...} 
} 

class B : public A{ 
    ... 
    void Foo(){ 
     A::Foo(); 
    } 
    void Boo(){...} 
} 

создать экземпляр B и вызвать его функцию Foo(). Когда эта функция вызывает A :: Foo(), будет ли использоваться метод Boo() класса A или B? Благодаря!

+2

Хорошо попробуй и посмотри, что получится! – Goz

+14

Мне не нравятся эти комментарии «попробуйте сами». То, что вы выясняете сами, - это то, что ваш компилятор делает под искусственными обстоятельствами вашего теста. Возможно, это не то, что вы хотели знать. Хотя я вижу, что в этом случае трудно представить, что компилятор ошибается, что, если ODdol, неуверенный о том, как работает «virtual», настроил тест, чтобы функция вызывалась из конструктора класса? Одна из таких ошибок может вернуть студента две недели. __В конце концов, этот сайт для получения ответов .__ Если вопросы вас раздражают, почему вы их читаете? – sbi

+0

@sbi: Нет, но это хорошая отправная точка. Как и в: у меня есть этот вопрос, и вот что я вижу. Это нормально? – Bill

ответ

9

Если вы не квалифицируете вызов функции с классом, все вызовы методов будут рассматриваться равны, то есть динамическая отправка, если виртуальная, статическая отправка если не виртуальный. Когда вы полностью квалифицируетесь с именем класса, метод, который вы вызываете, эффективно отключает механизм динамической рассылки и вводит прямой вызов метода.

class A{ 
    virtual void Foo(){ 
     Boo();   // will call the final overrider 
     A::Boo();  // will call A::Boo, regardless of the dynamic type 
    } 
    virtual void Boo(); 
}; 
class B : public A{ 
    void Foo(){ 
     //Foo();   // Would call the final overrider 
         // (in this case B: infinite recursion) 
     A::Foo();  // Will call A::Foo, even if the object is B 
    } 
    void Boo(); 
}; 

неявной this указатель не является важной частью обсуждения здесь, как точно то же самое происходит, когда вызов сделан с явным объектом:

B b; 
b.Foo(); // will call B::Foo -- note 1 
b.A::Foo(); // will call A::Foo 

Примечание 1: в этом примере, компилятор может выйти из динамического механизма отправки, поскольку он знает конкретный тип экземпляра (он видит определение и не является ссылкой/указателем), но вы можете предположить, что то же самое произойдет, если b является ссылкой или, что то же самое, если это было указатель с -> вместо .

2

С Boo() является виртуальным, вызывается переопределение производного класса.

Boo(); просто стенография для this->Boo();, где вы можете увидеть, что виртуальная функция вызывается через указатель. (имеет тип A* const в пределах Foo().) И виртуальные функции, вызываемые посредством ссылки или указателя, всегда будут вызывать переопределение в самом производном классе (кроме случаев, когда вызывается из конструктора или деструктора).

1

Внутри А,

virtual void Foo(){ 
     Boo(); 
    } 

транслируется в this->Boo(), а так как Бу объявляется виртуальным в А, методе производного класса Б вызывается. Не пытайтесь объявить Boo виртуальным в A только для экспериментов - вы увидите, что A-> Boo() получает вызов.

Arpan

Смежные вопросы