class CObject
{
public:
// Object model (types, destruction, allocation)
virtual CRuntimeClass* GetRuntimeClass() const;
virtual ~CObject(); //virtual destructors are necessary
...
...
};
为什么MFC的编写者认为virtual destructors are necessary
(虚拟的析构函数是必要的)?
在著名的VC教程 "精通Visual C++ for Windows 95/NT"(电子工业版,
1997年5月版,胡俭,丘宗明等著)第99页中有这样一段话:
“如果CObject的析构函数不是虚拟的,派生类就不会自动地得到虚拟的
析构函数,当对象撤消时就会带来问题——只有当前类的析构函数得到
调用而基类的析构函数就得不到调用。...”
我认为这段解释是这本很不错的书中一个不应出现的严重错误。其意思是说:
若:
class CBase
{
public:
~CBase() { ... };
...
};
class CChild : public CBase
{
public:
~CChild() { ... };
...
};
main()
{
Child c;
...
return 0;
}
上段代码在运行时,当栈框中的自动对象 c 被撤消时,只调用~CChild(),
而不调用~CBase()。
我想但凡对C++继承性理论有所了解的人都会立刻指出这是错误的。
由于在生成CChild对象c时,实际上在调用CChild类的构造函数之前必须首先
调用其基类CBase的构造函数,所以当撤消c时,也会在调用CChild类析构函数
之后,调用CBase类的析构函数(析构函数调用顺序与构造函数相反)。也就是说,
无论析构函数是不是虚函数,派生类对象被撤消时,肯定会依次上调其基类的
析构函数。
那么为什么CObject类要搞一个虚的析构函数呢?
仍以上面代码为例,如果main()中有如下代码:
...
CBase * pBase;
CChild c;
pBase = &c;
...
那么在、当pBase指针被撤消时,调用的是CBase的析构函数还是CChild的呢?
显然是CBase的(静态联编)。但如果把CBase类的析构函数改成virtual型,当
pBase指针被撤消时,就会先调用CChild类构造函数,再调用CBase类构造函数。
在这个例子里,所有对象都存在于栈框中,当离开其所处的作用域时,该对象
会被自动撤消,似乎看不出什么大问题。但是试想,如果CChild类的的构造函数
在堆中分配了内存,而其析构函数又不是virtual型的,那么撤消pBase时,将不
会
调用CChild::~CChild(), 从而不会释放CChild::CChild()占据的内存,造成内存
泄露。
而将CObject的析构函数设为virtual型,则所有CObject类的派生类的析构函数都
将
自动变为virtual型,这保证了在任何情况下,不会出现由于析构函数未被调用而
导致
的内存泄露。这才是MFC将CObject::~CObject()设为virtual型的真正原因。
分享到:
相关推荐
delete p[由于p被声明成父类指针,并且父类和子类的析构函数都非虚,因此delete操作只能根据p指针声明的类型来调用父类的析构函数]; std::cout ; } 6.请问下面这段程序的输出结果是_A_: A. 2,1, B. 2,2, C. 1,1,...
当某个类的实例被认为不再有效并符合析构条件时,.NET Framework类库的垃圾回收功能就会调用该类的析构函数实现垃圾回收,一个类只能有一个析构函数。一般准则是,除非有迫不得已的原因,不要使用析构函数,而应把...
系统首先为该动态对象调用析构函数,再释放其占用的内存 D.系统首先释放动态对象占用的内存,再为其调用析构函数 11、可在类外用p.a的形式访问派生类对象 p的基类成员a,其中a是( )。 A.私有继承的公用成员 B....
设有函数关系为y= ,下面选项中能正确表示上述关系为( c )。 (a) y = 1; (b) y = -1; if( x>=0 ) if( x!=0) if( x==0 )y=0; if( x>0 )y = 1; else y = -1; else y = 0 (c) if( x) (d) y = -...
子类继承父类大部分的资源,不能继承的有构造函数,析构函数,拷贝构造函数,operator=函数,友元函数等等 15.为什么要引入抽象基类和纯虚函数? 主要目的是为了实现一种接口的效果。 16.介绍一下模板和容器。如何...
//析构函数 virtual ~CSkinResource(); //基础接口 public: //释放对象 virtual VOID __cdecl Release() { return; } //接口查询 virtual VOID * __cdecl QueryInterface(REFGUID Guid, DWORD dwQueryVer); ...
main() //C++中main()函数默认为int型,而C语言中默认为void型。 { int a; cout; cin>>a; /*输入一个数值*/ cout; //输出并回车换行 return 0; } cin,cout,endl对象,他们本身并不是C++语言的组成部分。...
destructor(析构函数)什么时候应该是 virtual(虚拟)的?当 operator new(运算符 new)找不到足够的内存时它应该怎么办?类似这些的令人费神的细节是至关重要的,因为错误的做法几乎总是导致无法预料的,很可能...
//析构函数 virtual ~CPlatformResource(); //基础接口 public: //释放对象 virtual VOID __cdecl Release() { delete this; } //接口查询 virtual VOID * __cdecl QueryInterface(REFGUID Guid, DWORD ...
5.3 构造函数与析构函数 5.3.1 构造函数 5.3.2 析构函数 5.4 本章小结 5.5 上机练习 5.6 习题 第6章 域、属性与事件 6.1 域 6.1.1 域的初始化 6.1.2 只读域与readonly关键字 6.2 属性 6.2.1 属性的声明 6.2.2 属性...
15.4.4 虚析构函数 495 15.4.5 构造函数和析构函数中的虚函数 497 15.5 继承情况下的类作用域 497 15.5.1 名字查找在编译时发生 498 15.5.2 名字冲突与继承 498 15.5.3 作用域与成员函数 499 15.5.4 虚函数与作用域 ...
一个成员函数被声明为虚函数后,在同一类族中的类不能再定义一个非virtual的但与该虚函数具有相同的参数(包括个数和类型)和函数返回值类型的同名函数。 根据什么考虑是否把一个成员函数声明为虚函数? ①...
多态基类声明virtual析构函数 别让异常逃离析构构函数 不在构造析构过程中调用virtual函数 operator =返回对* this的引用 在operator =中处理自我赋值 复制对象时勿忘其每一个部份 以对象管理资源 在资源管理类中...
条款07:为多态基类声明virtual析构函数 declare destructors virtual in polymorphic base classes. 条款08:别让异常逃离析构函数 prevent exceptions from leaving destructors. 条款09:绝不在构造和析构过程中...
虚函数的实现原理,子类构造析构函数的调用顺序 虚函数怎么实现的 虚函数机制 虚函数的执行和类成员函数的执行在汇编的级别差了哪些指令 虚函数的作用和实现原理 构造中能不能调虚函数 析构中能不能调虚函数 C++模板...
6.13 何时调用构造函数与析构函数 6.14 使用数据成员和成员函数 6.15 微妙的陷阱:返回对Private数据成员的引用 6.16 通过默认的成员复制进行赋值 6.17 软件复用性 6.18 有关对象的思考:编写电梯模拟程序的类...
条款07:为多态基类声明Virtual析构函数 条款08:别让异常逃离析构函数 条款09:绝不在构造和析构过程中调用Virtual函数 条款10:令Operator=返回一个referenceto this 条款11:在Operator=中处理“自我赋值” ...
6.13 何时调用构造函数与析构函数 6.14 使用数据成员和成员函数 6.15 微妙的陷阱:返回对Private数据成员的引用 6.16 通过默认的成员复制进行赋值 6.17 软件复用性 6.18 有关对象的思考:编写电梯模拟程序的类...
面试题8:为什么要定义虚析构函数? 6 其他 6 4.3多态原理探究 6 4.3.1 多态的实现原理 6 4.3.2如何证明vptr指针的存在 6 4.3.3构造函数中能调用虚函数,实现多态吗 6 5、纯虚函数和抽象类 6 5.1基本概念 6 5.2抽象...
析构函数 Point(){} Point(int,int); ~Point(){} //++.--重载 Point& operator ++(); Point operator ++(int); Point& operator --(); Point operator --(int); //输出点坐标 void showPoint(); }; Point::Point(int...