首页 > 代码库 > 为什么 构造函数、内联函数、静态函数和友元函数不能是虚函数
为什么 构造函数、内联函数、静态函数和友元函数不能是虚函数
构造函数为什么不能是虚函数
C++
从存储空间角度,虚函数对应一个指向
vtable
虚函数表的指针,这大家都知道,可是这个指向vtable
的指针其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过vtable
来调用,可是对象还没有实例化,也就是内存空间还没有,怎么找vtable
呢?所以构造函数不能是虚函数。简单来说就是:虚函数的执行依赖于虚函数表。而虚函数表在构造函数中进行初始化工作,即初始化vptr
,让他指向正确的虚函数表。而在构造对象期间,虚函数表还没有被初始化,将无法进行。从使用角度,虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。所以没必要使构造函数为虚函数。
构造函数不需要是虚函数,也不允许是虚函数,因为创建一个对象时我们总是要明确指定对象的类型,尽管我们可能通过实验室的基类的指针或引用去访问它。但析构却不一定,我们往往通过基类的指针来销毁对象。这时候如果析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数。
从实现上看,
vbtl
在构造函数调用后才建立,因而构造函数不可能成为虚函数从实际含义上看,在调用构造函数时还不能确定对象的真实类型(因为子类会调父类的构造函数);而且构造函数的作用是提供初始化,在对象生命期只执行一次,不是对象的动态行为,也没有必要成为虚函数。当一个构造函数被调用时,它做的首要的事情之一是初始化它的
VPTR
。因此,它只能知道它是“当前”类的,而完全忽视这个对象后面是否还有继承者。当编译器为这个构造函数产生代码时,它是为这个类的构造函数产生代码——既不是为基类,也不是为它的派生类(因为类不知道谁继承它)。所以它使用的VPTR
必须是对于这个类的VTABLE
。而且,只要它是最后的构造函数调用,那么在这个对象的生命期内,VPTR
将保持被初始化为指向这个VTABLE
, 但如果接着还有一个更晚派生的构造函数被调用,这个构造函数又将设置VPTR
指向它的VTABLE
,等.直到最后的构造函数结束。VPTR
的状态是由被最后调用的构造函数确定的。(基类的构造函数会被调用多次,比如它自己和它的派生类,每次调用产生的VPTR
都可能不相同)这就是为什么构造函数调用是从基类到更加派生类顺序的另一个理由。但是,当这一系列构造函数调用正发生时,每个构造函数都已经设置VPTR
指向它自己的VTABLE
。如果函数调用使用虚机制,它将只产生通过它自己的VTABLE
的调用,而不是最后的VTABLE
(所有构造函数被调用后才会有最后的VTABLE
)。
inline
, static
, constructor
三种函数都不能带有virtual
关键字。 inline
是编译时展开,必须有实体; static
属于class
自己的,也必须有实体; virtual
函数基于vtable
(内存空间),constructor
函数如果是virtual
的,调用时也需要根据vtable
寻找,但是constructor
是virtual
的情况下是找不到的,因为constructor
自己本身都不存在了,创建不到class
的实例,没有实例,class
的成员(除了public static/protected static for friend class/functions
,其余无论是否virtual
)都不能被访问了。
C++
函数中那些不可以被声明为虚函数
常见的不不能声明为虚函数的有:普通函数(非成员函数);静态成员函数;内联成员函数;构造函数;友元函数。
1. 为什么C++
不支持普通函数为虚函数?
普通函数(非成员函数)只能被overload
,不能被override
,声明为虚函数也没有什么意思,因此编译器会在编译时静态绑定函数。
为什么
C++
不支持构造函数为虚函数?
这个原因很简单,主要是从语义上考虑,所以不支持。因为构造函数本来就是为了明确初始化对象成员才产生的,然而virtual function
主要是为了再不完全了解细节的情况下也能正确处理对象。另外,virtual
函数是在不同类型的对象产生不同的动作,现在对象还没有产生,如何使用virtual
函数来完成你想完成的动作。(这不就是典型的悖论)为什么
C++
不支持内联成员函数为虚函数?
内联函数就是为了在代码中直接展开,减少函数调用花费的代价,虚函数是为了在继承后对象能够准确的执行自己的动作,这是不可能统一的。(再说了,inline
函数在编译时被展开,虚函数在运行时才能动态的邦定函数)为什么
C++
不支持静态成员函数为虚函数?
静态成员函数对于每个类来说只有一份代码,所有的对象都共享这一份代码,他也没有要动态邦定的必要性。为什么
C++
不支持友元函数为虚函数?
因为C++
不支持友元函数的继承,对于没有继承特性的函数没有虚函数的说法。
为什么 构造函数、内联函数、静态函数和友元函数不能是虚函数