昨天提到了子在构造函数和析构函数中调用虚函数的问题。白天的时候翻了一下《深入理解C++对象模型》,结果还真发现一点儿有趣的东西。
文中如是说:很多C++新手会惊奇的发现纯虚函数竟然可以定义(在声明的基类中定义),并且可以被调用(静态调用)!看来我还是新手啊,废话少说,上代码!
#include <iostream> using namespace std; class Base{ public: Base(){} void callVirFunc(); virtual ~Base(){}; private: virtual void virFunc() = 0;//注意是私有的哦! }; class Derived:public Base{ public: Derived(){} private: virtual void virFunc();//这里也是私有的哦! }; void Base::virFunc(){ cout<<"Virtual function static defined in Base!"<<endl; } void Base::callVirFunc(){ virFunc();//调用Derived class中的实现版本 Base::virFunc();//调用Base class中的static版本 } void Derived::virFunc(){ cout<<"Virtual function defined in Derived!"<<endl; } int main(){ Base *pd = new Derived; pd->callVirFunc(); delete pd; return 0; }
运行结果:
:!./pure_virtual_func_test Virtual function defined in Derived! Virtual function static defined in Base!
例子中, Base class中的callVirFunc函数分别调用了在Base class中定义的纯虚函数版本和Derived class中的实现版本。神奇吧!
其实这个例子是很特殊的哦!它还是反映了另外一个有趣的问题哦!注意!Base class中的callVirFunc函数调用了Derived class中的私有虚函数!它竟然绕过了访问控制机制!对于这个问题,CSDN中的兄弟们进行了激烈的讨论(在这里http://topic.csdn.net/t/20040805/16/3245820.html)。我想说的是,从编译器的角度看,这是完全没有问题的,因为当前对象的类类型是Derived,它的vptr指向Derived的虚函数表。还有一个问题就是,在虚函数表中并没有访问控制信息,所以此时调用虚函数的时候,拿到的当然就是Derived的版本并正确执行喽。这种做法确实可以造成一些看起来诡异的程序行为,所以尽量避免这样做吧。如果想让程序更有序,更清晰,在虚函数中调用私有的本地函数是比较好的方式。