构造函数为什么一般不定义为虚函数

1> 使用角度:

  • 虚函数行为是在运行期间确定实际类型. 即虚函数调⽤只需要知道“部分的”信息,即只需要知道函数接口,⽽不需要知道对象的具体类型;
  • 但是,我们要创建⼀个对象的话,是需要知道对象的完整信息的. 特别是,需要知道要创建对象的确切类型,因此,构造函数不应该被定义成虚函数;

2> 以虚函数基于虚函数表说明

  • 而且从目前编译器实现虚函数进行多态的方式来看,虚函数的调用是通过实例化之后对象的虚函数表指针来找到虚函数的地址进行调用的,如果说构造函数是虚的,那么虚函数表指针则是不存在的,⽆法找到对应的虚函数表来调⽤虚函数,那么这个调⽤实际上也是违 反了先实例化后调用的准则


    3> 从实现上看,vtable 是在构造函数调用之后才建立,因而构造函数不可能为虚函数。


3.1 追问: 父类构造函数中是否可以调用虚函数? (重点)

可以。不过调用会屏蔽多态机制,最终会把基类中的该虚函数作为普通函数调用,而不会调用派生类中的被重写的函数。
原因在于 在定义子类对象的时候,会先调用父类的构造函数,而此时虚函数表以及子类对象还没有被初始化,为了避免调用到未初始化的内存,C++标准规范中规定了在这种情况下,即在构造子类时调用父类的构造函数,而父类的构造函数中又调用了虚成员函数,这个虚成员函数即使被子类重写,也不允许发生多态的行为。所以使用的是静态绑定,调用了父类的函数。


3.2 追问: static静态函数可以是虚函数吗? 为什么?

  • static成员不属于任何类对象或类实例,所以即使给此函数加上 virutal 也是没有任何意义的。
  • 静态与非静态成员函数之间有一个主要的区别。那就是静态成员函数没有this指针。所以无法访问虚函数表指针. 进而不能访问虚函数表。