一直对C++虚析构函数和引用技术不是特别清楚,所以到网上搜了些资料,写了一个简单的例子。
一、代码(hello.cpp)
#include<stdio.h>
class SimpleRefBase {
public:
SimpleRefBase():mRef_(1)
{
printf("func:%s() mRef_:%d\n",__FUNCTION__,mRef_);
}
virtual ~SimpleRefBase()
{
printf("func:%s() mRef_:%d\n",__FUNCTION__,mRef_);
}
void lock() {
++mRef_;//
printf("func:%s() mRef_:%d\n",__FUNCTION__,mRef_);
}
void unlock() {
--mRef_;
printf("func:%s() mRef_:%d\n",__FUNCTION__,mRef_);
if (mRef_ == 0) delete this;
}
private:
int mRef_;
};
class InheritedClass: public SimpleRefBase {
public:
InheritedClass() {
printf("func:%s()\n",__FUNCTION__);
}
~InheritedClass() {
printf("func:%s()\n",__FUNCTION__);
}
};
/////////////////////////////////
int main() {
SimpleRefBase * srf = new InheritedClass();
srf->unlock();
return 1;
}
/////////////////////////////////
调出VS2005下的[Visual Studio 2005 命令提示]编译文件,编译命令如下
cl hello.cpp
运行hello.exe结果如下:
func:SimpleRefBase::SimpleRefBase() mRef_:1
func:InheritedClass::InheritedClass()
func:SimpleRefBase::unlock() mRef_:0
func:InheritedClass::~InheritedClass()
func:SimpleRefBase::~SimpleRefBase() mRef_:0
二、分析过程
从log可以看出整个流程,基类构造→继承类构造→引用计数减一后删除自身→继承类析构→基类析构,这是正常的流程。
※1 但是,我如果将[virtual ~SimpleRefBase() ]前的virtual 去掉,运行结果如下:
func:SimpleRefBase::SimpleRefBase() mRef_:1
func:InheritedClass::InheritedClass()
func:SimpleRefBase::unlock() mRef_:0
func:SimpleRefBase::~SimpleRefBase() mRef_:0
从log中可以看出,基类构造→继承类构造→引用计数减一后删除自身→[继承类析构→]基类析构,没有运行继承类的析构。
※2 对于引用计数,如果是局部变量的话,不起作用。代码修改如下:
int main() {
InheritedClass srf;
return 1;
}
运行结果:
func:SimpleRefBase::SimpleRefBase() mRef_:1
func:InheritedClass::InheritedClass()
func:InheritedClass::~InheritedClass()
func:SimpleRefBase::~SimpleRefBase() mRef_:1
引用计数还为1的情况下,两个析构函数都走完了。
※3 将基类的virtual去掉,并且main中还是用局部变量
class SimpleRefBase {
public:
~SimpleRefBase()
{
printf("func:%s() mRef_:%d\n",__FUNCTION__,mRef_);
}
...
};
int main() {
InheritedClass srf;
return 1;
}
运行结果和※2的结果一样,对于局部变量来说,基类的虚析构函数加不加virtul都一样,但对于基类指针指向继承类这种情况,基类的虚析构函数很重要。
三、总结
1.基类析构函数加virtul,主要是对于基类指针指向继承类这种情况。对于局部变量的话,不管有没有基类虚析构函数,所有的析构函数都会被调用。
2.对于引用计数,也是对于new出来的对象。另外,当delete对象后(或者在将这块内存还给系统之前),调用析构函数,而不是直接将这块内存还给系统。
3.如果在类中加入virtual的话,会产生一个虚函数表,会增加对象的空间,所以,如果这个类不作为基类的话,没必要将析构函数写成虚函数。