2016-07-15 4 views
1
#include <iostream> 
#include <string> 
using namespace std; 

class Base { 
public: 
Base(const string& s): str(s) {cout<<"Base::ctor\n";} 
Base(const Base& b): str(b.str) {cout<<"Base::copy ctor\n";} 
virtual ~Base() {cout<<"Base::dtor\n";} 
void f1() {cout<<"Base::f1()\n"; f2();} //2 orders 
virtual void f2() {cout<<"Base::f2()\n";} 

private: 
string str; 
}; 

class Derived : public Base { 
public: 
Derived(const string& s): Base(s) 
{cout<<"Derived::ctor\n";} 
Derived(const Derived& d): Base(d) 
{cout<<"Derived::copy ctor\n";} 
~Derived() {cout<<"Derived::dtor\n";} 
virtual void f1() {cout<<"Derived::f1()\n"; f2();} 
void f2() {cout<<"Derived::f2()\n"; f1();} //jumps from here to Leaf's f1() 
}; 

class Leaf : public Derived { 
public: 
Leaf(const string& s): Derived(s) 
{cout<<"Leaf::ctor\n";} 
Leaf(const Leaf& dd): Derived(dd) 
{cout<<"Leaf::copy ctor\n";} 
~Leaf() {cout<<"Leaf::dtor\n";} 
void f1() {cout<<"Leaf::f1()\n"; f3();} 
void f3() {cout<<"Leaf::f3()\n";} 
}; 


int main() { 
Leaf * p = new Leaf("Hello"); 
Base * p2 = new Leaf(*p); 

p2->f1(); 

delete p2; 
delete p; 
return 0; 
} 

Здравствуйте,Кто вызывает функцию при вызове f1() через Derived :: f2()?

Этот вопрос экзамен сформулирован один, но это очень трудно для меня, чтобы найти правильный путь, чтобы описать его и искать его в Интернете.

в строке:

p2->f1(); 

выход:

Base::f1() 
Derived::f2() 
Leaf::f1() 
Leaf::f3() 

в Derived f2() есть призыв к f1(). кто будет называться? f1() типа Base или f1() листа? Из того, чему меня учили, компилятор всегда ищет функцию в типе слева. (Base * p2 = new Leaf (* p)) Но здесь я вижу, что он переходит в f1() класса Leaf. Я вижу, что это Лиф, но не понимаю, почему ...

спасибо за помощников!

+4

Не является ли ответ очевидным из вашего фактического результата? –

+0

Этот ответ - факт. Как я описал в своем посте, я не понимаю, почему он вызывает f1(), а не base f1() ... – EilonBom

+0

Что вы думаете о vtable? – curiousguy

ответ

2

Чтобы быстро ответить на ваш вопрос: Производный :: f1() вызывается в Derived :: f2().

Чтобы понять, почему это производный :: f1(), что называется, вы, вероятно, необходимо знание «имя C++ скрывается в наследство», которое вы можете сослаться на некоторые статьи в Интернете, как:

Кроме того, необходимо знание «неквалифицированное имя поиска», который вы можете обратиться к разделу «Статус определения функции» в этой веб-странице: Unqualified name lookup.

В целом, основные моменты:

  • В случае кода, Derived :: f1() скрывает Base :: f1(), что означает Базу :: f1() не видно членам Derived.
  • Звонок в f1() - это случайный случай поиска неквалифицированных имен.
  • Имена, как правило, выглядят сверху от внешнего пространства. Когда f1() вызывается в Derived :: f2(), компилятор сначала ищет в самой внутренней области, которая является самим производным :: f2(); затем весь класс Derived scope. Поскольку f1() можно найти в области Derived, он становится тем, который вызывается.
  • Возможно, вы думаете, что Base :: f1() выглядит так, будто он сидит на одном уровне с Derived :: f1() из-за наследования, а затем задается вопросом, почему Base :: f1() не вызывается. Напомнить имя скрывается.

Процесс вызова должен выглядеть следующим образом:

  1. В главном(), p2->f1(); выполняется.
  2. Поскольку p2 является указателем на базу, имя «f1» выполняется в списке методов базы.
  3. Обратите внимание, что Base :: f1() НЕ виртуальный, поэтому Base :: f1() вызывается ("Base :: f1()"). Да, f1() объявляется как виртуальный в Derived, но это не влияет на виртуальную таблицу Base.
  4. Base :: f1() вызывает f2, который является виртуальным методом Base. Поскольку f2 только переопределяется в Derived, Derived :: f2() - это тот, который на самом деле называется («Производный :: f2()»).
  5. Производный :: f2() вызывает f1(), который фактически является производным :: f1(). Поскольку Derived :: f1() объявлен как виртуальный и переопределен в Листе, в конечном итоге его вызывает Leaf :: f1() («Leaf :: f1()»).
  6. Лист :: f1() вызывает f3(), который является листом :: f3(). f3() - метод, который только Лиф имеет так называемый («Лист :: f3()»).
+0

Спасибо, яобин! очень полезно ... Поэтому я пришел к выводу, что если метод вызывается в классе (например, Derived), он будет вызывать тот же метод классов - что означает Derived :: f2() (а затем, если есть наследование и т. д.))? – EilonBom

+0

@EilonBom Я отредактировал свой ответ и добавил некоторые ссылки, которые вы можете изучить. Надеюсь, они могут дать вам лучшее представление о том, что происходит за сценой. Это должно ответить на ваши вопросы как в должности, так и в комментарии. – yaobin

+0

«поиск адреса f1» <- Не происходит поиска адресов, мы выполняем поиск по имени. – Barry