构造函数不能为虚函数,因为虚函数依赖虚函数表,构造函数尚未执行时,指向虚函数表的指针还不存在,因此显然构造函数无法成为虚函数。另外子类名字与父类不同,类的构造函数无法继承,更不能通过指针或引用去调用,因此跟虚函数也沾不上边。但是构造函数能否调用虚函数?按理说,构造函数没执行完,虚函数表都没有呢还。
#include <stdio.h> class A { public: A(){} ~A(){} virtual void print(){printf("Base\n");} }; class B:public A { public: B(){} ~B(){} void print(){printf("B\b");} }; class C:public A { public: C(){} ~C(){} void print(){printf("C\b");} }; int main() { A a; B b; C c; A *p=NULL; int choice; printf("Input choice="); scanf("%d",&choice); switch(choice) { case 1: p=&a; break; case 2: p=&b; break; case 3: p=&c; break; default: p=&a; } p->print(); getchar(); return 0; }
结果:
class A { public: A() { print(); } ~A(){} virtual void print(){printf("Base\n");} }; class B:public A { public: B():A() { print(); } ~B(){} void print(){printf("B\b");} }; class C:public A { public: void print(){printf("C\b");} C() :A() { print(); } ~C(){} };
class A { public: A() { print(); } ~A(){} virtual void print(){printf("Base\n");} }; class B:public A { public: B():A() { print(); } ~B(){} void print(){printf("B\b");} }; class C:public A { public: void print(){printf("C\b");} C() :A() { print(); } ~C(){} }; int main() { A a; printf("\n"); B b; printf("\n"); C c; return 0; }
但是有几次只输出了Base,Base,Base。
参考资料:
http://dev.yesky.com/441/2033941.shtml
这里给出的解释是说,构造函数需要调用基类的构造函数,然后再执行本身的构造部分,所以呢,当本身的那部分还没开始的时候,编译器只认为这是一个基类对象。于是,就会调用基类对应的函数了!面试的时候只想着按指针来找,结果杯具了。考官gg说,你回去跑跑看。幸好后来让我写对象模型写对了。
基类构造期间,虚函数从来不会向下匹配(go down)到派生类。取而代之的是,那个对象的行为就好像它的类型是基类。非正式地讲,基类构造期间,虚函数禁止。 这个表面上看起来匪夷所思的行为存在一个很好的理由。因为基类的构造函数在派生类构造函数之前执行,当基类构造函数运行时,派生类数据成员还没有被初始化。如果基类构造期间调用的虚函数向下匹配(go down)到派生类,派生类的函数理所当然会涉及到本地数据成员,但是那些数据成员还没有被初始化。这就会为未定义行为和悔之晚矣的调试噩梦开了一张通行证。调用涉及到一个对象还没有被初始化的部分自然是危险的,所以 C++ 告诉你此路不通。
在实际上还有比这更多的更深层次的原理。在派生类对象的基类构造期间,对象的类型是那个基类的。不仅虚函数会解析到基类,而且语言中用到运行时类型信息(runtime type @R_826_4045@ion)的配件(例如,dynamic_cast和 typeid),也会将对象视为基类类型。在我们的例子中,当 Transaction 构造函数运行初始化 BuyTransaction 对象的基类部分时,对象的类型是 Transaction。C++ 的每一个配件将以如下眼光来看待它,并对它产生这样的感觉:对象的 BuyTransaction 特有的部分还没有被初始化,所以安全的对待它们的方法就是视若无睹。在派生类构造函数运行之前,一个对象不会成为一个派生类对象。
同样的原因也适用于析构过程。一旦派生类析构函数运行,这个对象的派生类数据成员就被视为未定义的值,所以 C++ 就将它们视为不再存在。在进入基类析构函数时,对象就成为一个基类对象,C++ 的所有配件——虚函数,dynamic_casts 等——都如此看待它。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。