什么函数不能是虚函数?为什么析构必须是虚函数?

虚函数

虚函数:被virtual修饰的基类成员函数。

纯虚函数:

  • 例如virtual void foo() = 0。纯虚函数所在类称为**“抽象类”**,抽象类不能实例化出对象,它的子类必须重写纯虚函数,否则依然是抽象类。
  • 纯虚函数可以有函数体,但是没有意义。

注:只在子类中声明virtual,无法构成虚函数。

不能声明为虚函数的函数

1、普通函数
普通函数不属于类。

2、构造函数
虚函数是为了依据不同的对象来产生不同的状态,但是前提是得有这个对象,而对象的产生必须依靠构造函数;其次,虚函数表指针的初始化也在构造函数的初始化列表阶段,二者矛盾了。

3、内联成员函数
内联函数是在编译期间直接在调用位置展开代码,而虚函数是在运行时通过不同对象来判断函数的调用;其次,内联函数没有地址,不能形成虚表。

4、静态成员函数
static成员函数是类的所有对象共享的,而虚函数是针对不同对象构成多态,二者矛盾;其次,静态成员函数没有this指针,无法访问虚函数表。

5、友元函数
友元函数不属于类的成员函数,不能被继承,更不能声明为虚函数。

协变

虚函数重写必须满足:返回值类型、函数名、参数列表都相同,但是协变和析构函数是例外。

如果基类的虚函数返回的是一个基类的指针或引用,派生类的虚函数返回的是一个派生类的指针或引用,那么这两个函数尽管返回值类型不同,但是依然构成虚函数,这种称为协变

而虚构函数会被编译器统一命名为destructor,因此满足虚函数的条件。

构造函数/析构函数内部可以调用虚函数实现多态吗

语法上支持,但是会失去多态的效果,因为:

  • 构造子类先调用父类的构造函数,相当于父类构造时子类还完全不存在,没有虚函数表指针也就无法构成多态。
  • 析构子类则先调用子类的析构函数,然后调用父类的。那么当父类析构时子类依旧不存在,所以无法构成多态。

为什么有的析构函数必须设置成虚函数

如果基类的析构函数是用virtual修饰的虚函数,那么无论派生类的析构函数是否有virtual修饰,它都是虚函数。原因是:

  1. 只要基类虚函数有virtual修饰,那么派生类的virtual可以省略。
  2. 析构函数的名称会被编译器统一处理成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的空间就造成了内存泄漏。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白龙码~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值