一、今天在写code的时候发现了如果在基类中调用了virtual 函数,而子类中如果重定义了这个virtual函数的话,那么在子类中的constructor实际上在创建基类的那一部分的时候,仍然调用的是基类中的那个virtual函数,而不是子类中的那个。
有一个非常重要的参考网站:http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.5
在23.5和23.6中说到了这种情况的原因和如何可以使在构造函数里面就能够调用子类的virtual函数。
举个例子吧:
#include <iostream>
using std::cout;
class Base {
Base() { foo(); }
virtual void foo() { cout << "Base::foo()" << endl; }
};
class Derived : public Base {
Derived() { foo(); }
virtual void foo() { cout << "Derived::foo()" << endl; }
};
那么在输出的时候,输出会是下面这样:
Base::foo()
Derived::foo()
而不是两个Derived::foo()
解决方案请参考上面的参考网站里面的23.6,或者直接在构造函数里面再调用一次子类的virtual函数。
二、关于C++里面的virtual函数的动态调用的编译器实现。
参考网站:http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.3
在20.3和20.4里面讲到了当编译器遇到virtual函数的时候,是如何去使得程序能够动态的调用正确的函数的。
实现原理其实是这样的:
- 当编译器遇到类定义里面的第一个virtual函数的时候,会在实际声称的代码里面隐藏的声明一个v_table的表,这个表里面存在的是指向当前类的virtual函数的函数指针。
- 在遇到这个类的实例声明的时候,会隐藏的声明一个v_pointer的指针,指向这个实例的类的v_table。
那么当在程序运行的时候,程序会执行一个fetch,fetch,run的顺序来执行特定的virtual函数。假定基类Base,子类Derived,virtual函数为foo()。
在Base * p = new Derived();
p->foo();
遇到上面这句函数调用的时候:
- fetch: 首先电脑由v_pointer指针获取v_table。这里的v_table是Derived的v_table但是结构和Base的v_table的结构是一样的。
- fetch: 电脑在v_table里面找到对应foo()的函数指针,然后载入该函数的实际地址。
- run: 由载入的函数地址调用实际的函数。
PS: C++太强大了………………