派生类有两部分:基类和派生类自己的部分
派生类在构造时:基类的构造函数构造基类部分,派生类自己的构造函数构造派生类部分,析构同样
#include<iostream>
using namespace std;
class Base
{
public:
Base(int a) :ma(a)
{
cout << "Base::Base()" << endl;
}
~Base()
{
cout << "Base::~Base()" << endl;
}
virtual void show()
{
cout << "Base::show()" << endl;
}
protected:
int ma;
};
class Derive:public Base
{
public:
Derive(int b) :mb(b), Base(b)
{
cout << "Derive::Derive()" << endl;
}
~Derive()
{
cout << "Derive::~Derive()" << endl;
}
void show()
{
cout << "Derive::show()" << endl;
}
private:
int mb;
};
int main()
{
Base* pb = new Derive(10);
pb->show();
delete pb;
}
运行结果:
通过测试,发现派生类对象未析构,产生内存泄露。
通过在派生类中加入new的重载
void* operator new(size_t size)
{
void* ptr = malloc(size);
cout << "newaddr:" << ptr << endl;
return ptr;
}
在基类中加入delete的重载
void operator delete(void* ptr)
{
cout << "deleteaddr:" << ptr << endl;
free(ptr);
}
测试结果:
分析原因:
Base* pb = new Derive(10);
pb->show();
delete pb;
在此为基类指针指向派生类对象,但是基类指针只用到(即只指向)基类部分。在new的时候内核维护了一个数据结构来记录开辟时的首地址和总大小。
可是构造的时候从vfptr开始构造,但是析构是时候从基类部分开始析构了。
释放的地址与开辟时的地址进行匹配,匹配不到,编译器认为释放的是非法地址,所以程序崩溃。
#include<iostream>
using namespace std;
class Base
{
public:
Base(int a) :ma(a)
{
cout << "Base::Base()" << endl;
}
virtual ~Base()
{
cout << "Base::~Base()" << endl;
}
virtual void show()
{
cout << "Base::show()" << endl;
}
protected:
int ma;
};
class Derive:public Base
{
public:
Derive(int b) :mb(b), Base(b)
{
cout << "Derive::Derive()" << endl;
}
~Derive()
{
cout << "Derive::~Derive()" << endl;
}
void show()
{
cout << "Derive::show()" << endl;
}
private:
int mb;
};
int main()
{
Base* pb = new Derive(10);
pb->show();
delete pb;
//实际在此编译器为我们做了pb->~Base() 由于~Base()不是虚函数,
//所以在此产生的是静多态
//在销毁是值调用了基类的析构函数,派生类对象未进行析构,内存泄露
//那如何修改呢???
//1、强转
Derive* pd = (Derive*)pb;
delete pd;
//2、利用虚函数机制
//在基类析构函数前加上virtual关键字产生虚析构,则符合动多态的发生条件
//再delete pb时就会进行操作:pb->~Derive(),
//且会自动调用基类的析构函数,在此就会call eax,而不是函数入口地址
}
运行结果: