一直以来C++的基础还停留在学生时代,
由于理论基础的不扎实,在项目中析构函数多重集成后犯了一个低级的理论错误,特此记录,引以为戒。
废话少说,看图说话。
首先定义了一个类,然后继承他,
#include <iostream>
class CPU
{
public:
CPU(){ std::cout << "Struct CPU" << std::endl; }
~CPU(){ std::cout << "Detruct CPU" << std::endl; }
};
class MultiCoreCPU : public CPU
{
public:
MultiCoreCPU(){ std::cout << "Struct MultiCoreCPU" << std::endl; }
~MultiCoreCPU(){ std::cout << "Detruct MultiCoreCPU" << std::endl; }
};
int main()
{
CPU *a = (CPU *)(new MultiCoreCPU);
delete a;
}
运行结果:
Struct CPU
Struct MultiCoreCPU
Detruct CPU
MultiCoreCPU的析构函数没有调用了!!
上网找了一下C++基础理论看看,这是C++继承的特性,果然既是优势,又是陷阱啊!!
C++的派生机制是,当调用类析构函数时,会从继承类的整个家族中,从第一个不是虚析构的孙子开始,一直调到祖宗的析构函数去。
这个案例中,由于祖宗CPU的析构不是虚函数,因此就会从他开始调,忽略了他的孙子MultiCoreCPU。
若要C++别落下孙子MultiCoreCPU的析构,
应该再孙子的析构函数前也加入虚函数定义。
#include <iostream>
class CPU
{
public:
CPU(){ std::cout << "Struct CPU" << std::endl; }
virtual ~CPU(){ std::cout << "Detruct CPU" << std::endl; } // 注意这里
};
class MultiCoreCPU : public CPU
{
public:
MultiCoreCPU(){ std::cout << "Struct MultiCoreCPU" << std::endl; }
virtual ~MultiCoreCPU(){ std::cout << "Detruct MultiCoreCPU" << std::endl; } // 为了避免龟孙子又有孩子,出现同样的继承问题,一同加上
};
int main()
{
CPU *a = (CPU *)(new MultiCoreCPU);
delete a;
}
好了,这个是我的问题的起因。
单纯这个问题要找出来也不难,我的问题更加的隐蔽。
当超过两重继承的时候,很容易就会掉以轻心了。
#include <iostream>
class CPU
{
public:
CPU(){ std::cout << "Struct CPU" << std::endl; }
// virtual ~CPU(){ std::cout << "Detruct CPU" << std::endl; } // 祖宗没有显式定义析构函数
};
class MultiCoreCPU : public CPU
{
public:
MultiCoreCPU(){ std::cout << "Struct MultiCoreCPU" << std::endl; }
virtual ~MultiCoreCPU(){ std::cout << "Detruct MultiCoreCPU" << std::endl; }
};
class IntelI5 : public MultiCoreCPU
{
public:
IntelI5(){ std::cout << "Struct IntelI5" << std::endl; }
virtual ~IntelI5(){ std::cout << "Detruct IntelI5" << std::endl; }
};
int main()
{
CPU *a = (CPU *)(new IntelI5);
delete a;
}
这个时候,由于祖宗没有显式地定义虚析构函数,因此编译器不会把他定义为虚函数,
结果就悲剧了,孙子里面整个家族都没有调用析构函数。
运行结果:
Struct CPU
Struct MultiCoreCPU
Struct IntelI5
刚好在项目中各个构造函数中都用到了堆的内存申请,然后就是一大堆的内存泄漏,BIEBIEBEIBE。
文末介绍一个单体的用法,
有些时候,程序定义一个类,全局只能存在一个对象,不能存在多个,
这个时候通常会用静态指针去实现,
而这个类又是继承过来的,怎么让他的祖宗也不让定义呢?把所有的构造函数定义成保护类型!!
#include <iostream>
class CPU
{
protected:
CPU(){ std::cout << "Struct CPU" << std::endl; }
public:
virtual ~CPU(){ std::cout << "Detruct CPU" << std::endl; }
};
class MultiCoreCPU : public CPU
{
protected:
MultiCoreCPU(){ std::cout << "Struct MultiCoreCPU" << std::endl; }
public:
virtual ~MultiCoreCPU(){ std::cout << "Detruct MultiCoreCPU" << std::endl; }
};
static void *
_singleton = NULL;
class IntelI5 : public MultiCoreCPU
{
protected:
IntelI5(){ std::cout << "Struct IntelI5" << std::endl; }
public:
virtual ~IntelI5(){ std::cout << "Detruct IntelI5" << std::endl; }
public:
static IntelI5 *
Singleton(){
if(!_singleton)
{
_singleton = (void *)(new IntelI5);
}
return (IntelI5 *)_singleton;
}
};
int main()
{
CPU *a = (CPU *)(IntelI5::Singleton());
delete a;
}
这样,当你调用new CPU这样的语句时候,编译器就主动报错去阻止你了。

最后赞一下SUBLIME EDIT,类定义没有写分号时候,通过颜色给予了我强烈的谴责