C++将析构函数定义成virtual的原因
来源:互联网 发布:怎么在淘宝买电棒 编辑:程序博客网 时间:2024/06/11 21:52
疑问:为什么在C++的实际使用中继承子类的虚构函数有的时候需要添加virtual有时候不需要添加virutal
1. 一般来说,如果一个类要被另外一个类继承,而且用其指针指向其子类对象时,例如:
A* d = new B();(假定A是基类,B是从A继承而来的派生类)
那么其(A类)析构函数必须是虚的,否则在delete d时,B类的析构函数将不会被调用,因而会产生内存泄漏和异常;
2. 在构造一个类的对象时,先构造其基类子对象,即调用其基类的构造函数,然后调用本类的构造函数;销毁对象时,先调用本类的析构函数,然后再调用其基类的构造函数;
举个例子:
#include "stdio.h"
#include <iostream>
class Animal
{
char *ap;
public:
Animal()
{
ap = new char;
std::cout << "Animal ctor" << std::endl;
}
virtual void foo()
{
std::cout << "Animal::foo" << std::endl;
}
virtual ~Animal()
{
std::cout << "Animal dtor" << std::endl;
delete ap;
}
};
class Dog : public Animal
{
char *dp;
public:
Dog()
{
dp = new char;
std::cout << "Dog ctor" << std::endl;
}
virtual void foo()
{
std::cout << "Dog::foo" << std::endl;
}
virtual ~Dog()
{
delete dp;
std::cout << "Dog dtor" << std::endl;
}
};
int main(int argc,char* argv[])
{
Animal *pa = new Dog();
pa->foo();
delete pa;
return 0;
}
代码输出如下:
delete pa 实际上相当于:pa->~Animal();释放pa所指向的内存(或许是free(pa))。
在这里,因为~Animal()是virtual的,尽管是通过Animal类型的指针调用的,根据v-table的信息,~Dog()被正确调用到。如果把virtual属性去掉,那么被调用的是~Animal(),Dog类的构造函数被调用而析构函数未被调用,构造函数中分配的资源没有释放,从而产生了内存泄漏。析构函数缺省声明为virtual,就可以避免这一问题。
如果把代码中的红色的“virutual”(基类Animal析构函数前的virtual)删除的话,输出如下:
明显Dog的析构函数没有被调用,内存泄漏了
可另一个问题是,有时virtual是不需要的。如果一个类不会被继承,比如一个utility类,该类完全是静态方法;或者一些类尽管可能会被继承,但不会被使用成多态的,即除了析构函数外,没有其他的方法是virtual的,这时就可以把virtual属性去掉。
去掉析构函数的virtual属性后,因为该类中没有其他的virtual函数,所以编译时不会生成v-table,这样就节省了编译时间,并减少了最终生成的程序的大小。更重要的是,遵从这一规则,给该类的维护者一个信息,即该类不应被当作多态类使用。
- C++将析构函数定义成virtual的真正原因
- C++将析构函数定义成virtual的原因
- C#&&Java-----C#中和Java中把主函数定义成静态成员函数的原因
- 把一个类的析构函数定义成virtual
- 析构函数(Virtual)的原因
- C++中析构函数定义成虚函数的原因
- C++中析构函数定义成虚函数的原因
- C++中析构函数需要定义成虚函数的原因
- 《Effective C++》读书笔记之item36:绝不重新定义继承而来的non-virtual函数
- Effective C++:条款36:绝不重新定义继承而来的non-virtual函数
- c++:不要重新定义继承而来的non-virtual函数
- 绝对不要重新定义继承而来的non-virtual函数(Effective C++_36)
- 《Effective C++》36:绝不重新定义继承而来的non-virtual函数
- 读书笔记《Effective C++》条款36:绝不重新定义继承而来的non-virtual函数
- C++之绝不重新定义继承而来的non-virtual函数(36)---《Effective C++》
- inline内联函数不能为virtual虚函数的原因
- C/C++—— C++中定义虚析构函数的原因
- C#virtual详解,virtual和构造函数的问题
- webpack打包
- K8s kubectl get操作
- 数据盘分区以及格式化
- jmeter检查点
- 基于 UAP 的 Web Service 开发
- C++将析构函数定义成virtual的原因
- GPIO
- javascript权威指南--第七章
- CRC校验笔记
- Caused by: org.springframework.beans.factory.BeanCreationException
- go语言中的互斥 + defer
- js继承方法的总结
- php stdClass Object转array array解析
- PHP cgi fastcgi & php-fpm 的关系以及理解