何时令什么是析构函数数为virtual呢??

1851人阅读
基础知识(9)
#include&iostream&
class Base
virtual ~Base(){}
//基类的析构函数应该声明为虚析构函数。
virtual void
Test(){cout&&&Base Test&&&}
class Derived:public Base
Derived(){}
~Derived(){cout&&&delete Derived&&&}
void Test(){cout&&&Derived Test&&&}
void main()
Base* pBase=new Derived();
//父类的指针指向派生类的对象。
pBase-&Test();
delete pB //如果没有Base基类的析构函数没有声明为virtual,是不会执行到子类的析构函数的。
//所以将父类的析构函数声明为虚函数,作用是用父类的指针删除一个派生类对象时,派生类对象的析构函数会被调用。
}将父类的析构函数声明为virtual是为了删除父类指针时可以调用到子类的析构函数。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:214899次
积分:2623
积分:2623
排名:第9681名
原创:65篇
转载:28篇
评论:19条
(2)(10)(8)(1)(5)(4)(3)(3)(2)(1)(7)(7)(2)(1)(9)(2)(5)(9)(3)(1)(1)(11)Learning speed & Changing speed有继承的C++析构函数一定要用virtual - 1957 - 博客园
无聊蛋疼的1957写的低端博客
posts - 214, comments - 37, trackbacks - 0, articles - 1
先补下virtual是啥
虚函数是指一个类中你希望重载的成员函数,当你用一个基类指针或引用指向一个继承类对象的时候,你调用一个虚函数,实际调用的是继承类的版本。&
先贴个代码,再解释
#include &iostream&
using namespace
class Base
Base(){cout&&"Base Construct"&&};
~Base(){cout&&"Base destroy"&&}
class A : public Base
A(){cout&&"A Construct"&&}
~A(){cout&&"A destroy"&&}
class Base1
Base1(){cout&&"Base1 Construct"&&};
~Base1(){cout&&"Base1 destroy"&&}
class A1 : public Base1
A1(){cout&&"A1 Construct"&&}
~A1(){cout&&"A1 destroy"&&}
int main()
Base* p = new A;
cout&&"======================"&&
Base1* p1 = new A1;
delete p1;
Base Construct
A Construct
Base destroy
======================
Base1 Construct
A1 Construct
A1 destroy
Base1 destroy
在代码尾部的注释就是输出。
Base的析构函数没有virtual
Base1的析构函数有virtual
Base* p = new A
这个过程只调用了Base的析构函数,没有调用A的析构函数。
这样在实际应用中会有不确定的后果,可能会memory leak
应该在A的析构函数中我们可能会销毁一些其他的资源,而这里并未调用。
所以要给Base的析构函数以virtual属性。对C++的领悟与想法(21)
1. 一般来说,如果一个类要被另外一个类继承,而且用其指针指向其子类对象时,如题目中的A* d = new B();(假定A是基类,B是从A继承而来的派生类),那么其(A类)析构函数必须是虚的,否则在delete d时,B类的析构函数将不会被调用,因而会产生内存泄漏和异常;
2. 在构造一个类的对象时,先构造其基类子对象,即调用其基类的构造函数,然后调用本类的构造函数;销毁对象时,先调用本类的析构函数,然后再调用其基类的构造函数;
3. 题目给出的代码是可以编译的,但会出现运行时错误。错误出现在这一句。为讨论方便,我们不妨将A类和B类改写如下:
&&&&&&& cout && &A::~A& &&
class B : public A
&&& virtual ~B()
&&&&&&& cout && &B::~B& &&
那么A* d = new B();这一句的左边所产生B的对象的内存结构如下:
而A对象的内存结构如下:
可见d只能找到a和A类的析构函数,而无法找到B对象的析构函数,所以当的时候,B对象所占用的内存就此被泄漏掉了,也从而产生了异常。
如果将A类的析构函数设为虚的,那么A类对象的内存结构将为:
B类对象的内存结构为:
此时通过A* d = new B();,A对象的内存结构中的vfptr,即虚函数表指针,就是B对象的vfptr(B对象的vfptr被bitwise copy,即浅拷贝到A对象的vfptr。如B是从A虚继承而来的,则需要加一个offset,情况要更复杂,见
),因此,A对象的vfptr所指向的是B对象的虚函数表,而B的析构函数位于书函数表0的位置,因此,这样就可以通过A类对象的指针d,找到B类对象的析构函数,从而在delete
时,可以销毁B对象,而不会产生内存泄漏和异常。
事实上,该题目只要将A中的析构函数设成虚的,B类中的析构函数前面的virtual关键字不管是否存在,其析构函数也一定是虚的,C类同此道理。因此,得到结论就是,只要能够保证继承关系中最高的基类的析构函数是虚的,那么就不会产生前面所谈及的问题。这就是为什么在想使用多态特性的时候,需要将基类的析构函数设成虚的真正原因。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:61472次
排名:千里之外
原创:19篇
转载:10篇
(3)(5)(21)1 #include &iostream&
2 using namespace
4 class Father{
~Father(){
cout&&"Father's Desconstruct Called."&&
12 class Son : public Father{
13 public:
cout&&"Son's Desconstruct Called."&&
19 int main(){
Father *f = new Son();
system("pause");
上面的代码,用父类指针指向new出来来的之类对象,这样是没问题的,接着,对这个父类指针变量进行了delete操作。上面的输出结果是什么呢?
Father's Desconstruct Called.
可见,子类的析构函数没有被调用,那如果子类中new了内存,那么那块内存就丢了。如何保证在删除父类指针的时候,子类的析构函数也被调用呢?看如下代码:
1 #include &iostream&
2 using namespace
4 class Father{
virtual ~Father(){
cout&&"Father's Desconstruct Called."&&
12 class Son : public Father{
13 public:
cout&&"Son's Desconstruct Called."&&
19 int main(){
Father *f = new Son();
system("pause");
输出是什么呢?
Son's Desconstruct Called.
Father's Desconstruct Called.
这就是动态联编的析构函数,至于为什么这样就可以调用子类的析构函数了,这就牵涉到另一个概念:虚函数表。具体请参照:
阅读(...) 评论()}

我要回帖

更多关于 什么是析构函数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信