什么函数不能是虚函数?为什么析构必须是虚函数?
Posted 白龙码~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么函数不能是虚函数?为什么析构必须是虚函数?相关的知识,希望对你有一定的参考价值。
文章目录
虚函数
虚函数:被virtual
修饰的基类成员函数。
纯虚函数:
- 例如
virtual void foo() = 0
。纯虚函数所在类称为**“抽象类”**,抽象类不能实例化出对象,它的子类必须重写纯虚函数,否则依然是抽象类。 - 纯虚函数可以有函数体,但是没有意义。
注:只在子类中声明virtual,无法构成虚函数。
不能声明为虚函数的函数
1、普通函数
普通函数不属于类。
2、构造函数
虚函数是为了依据不同的对象来产生不同的状态,但是前提是得有这个对象,而对象的产生必须依靠构造函数;其次,虚函数表指针的初始化也在构造函数的初始化列表阶段,二者矛盾了。
3、内联成员函数
内联函数是在编译期间直接在调用位置展开代码,而虚函数是在运行时通过不同对象来判断函数的调用;其次,内联函数没有地址,不能形成虚表。
4、静态成员函数
static成员函数是类的所有对象共享的,而虚函数是针对不同对象构成多态,二者矛盾;其次,静态成员函数没有this指针,无法访问虚函数表。
5、友元函数
友元函数不属于类的成员函数,不能被继承,更不能声明为虚函数。
协变
虚函数重写必须满足:返回值类型、函数名、参数列表都相同,但是协变和析构函数是例外。
如果基类的虚函数返回的是一个基类的指针或引用,派生类的虚函数返回的是一个派生类的指针或引用,那么这两个函数尽管返回值类型不同,但是依然构成虚函数,这种称为协变。
而虚构函数会被编译器统一命名为destructor
,因此满足虚函数的条件。
构造函数/析构函数内部可以调用虚函数实现多态吗
语法上支持,但是会失去多态的效果,因为:
- 构造子类先调用父类的构造函数,相当于父类构造时子类还完全不存在,没有虚函数表指针也就无法构成多态。
- 析构子类则先调用子类的析构函数,然后调用父类的。那么当父类析构时子类依旧不存在,所以无法构成多态。
为什么有的析构函数必须设置成虚函数
如果基类的析构函数是用virtual修饰的虚函数,那么无论派生类的析构函数是否有virtual修饰,它都是虚函数。原因是:
- 只要基类虚函数有
virtual
修饰,那么派生类的virtual
可以省略。 - 析构函数的名称会被编译器统一处理成destructor,因此它们完全满足名称、参数列表、返回值类型相同的条件。
在如下情况,第二点格外重要:
class A
public:
~A()
;
class B :public A
public:
B()
_a = new int[100];
~B()
delete[]_a;
private:
int* _a;
;
int main()
A* p = new B;
delete p;
return 0;
如果析构函数不定义成虚函数,那么这里就构成不了多态,我们delete p
只会调用p类型的析构函数,即~A()
,而B中new
的空间就造成了内存泄漏。
以上是关于什么函数不能是虚函数?为什么析构必须是虚函数?的主要内容,如果未能解决你的问题,请参考以下文章