动态内存分配:
①派生类不使用new
Q:是否需要为派生类重新定义复制构造函数,复制运算符,析构函数?
A:不需要,子类中默认的复制构造函数,复制赋值运算符,析构函数就能完成所有的工作,虽然是浅层
复制,但是由于子类中没有申请动态内存,子类默认的复制构造函数,复制赋值运算符,析构函数都将
自动调用父类的复制构造函数,复制赋值运算符,析构函数,而父类的这些成员都是深复制的即可
②派生类使用new
Q:是否需要为派生类重新定义复制构造函数,复制运算符,析构函数?
A:需要!!
(Ⅰ)如何定义派生类复制构造函数
初始化列表显式调用基类的复制构造函数,并执行派生类新增数据的深度复制
Base::Base(const Base & o)
{
str = new char[std::strlen(o.str)+1];
std::strcpy(str,o.str);
}
Sub::Sub(const Sub & o) : Base(o)//显式调用基类的复制构造函数
{ 下面是派生类成员的深度复制
sub_str = new char[std::strlen(o.sub_str)+1];
std::strcpy(sub_str,o.sub_str);
}
假设sub_str是派生类的新增的指针成员,str是基类的指针成员,子类的复制构造函数显式调用父类的
复制构造函数,对派生类的成员执行深度复制即可
(Ⅱ)如何定义派生类复制赋值运算符
Base & Base::operator=(const Base & o)
{
if(this!=&o)
{
delete[] str;
str = new char[std::strlen(o.str)+1];
std::strcpy(str,o.str);
}
return *this;
}
Sub & Sub::operator=(const Sub & o)
{
if(this==&o)
{
delete[] sub_str;
/*#1*/Base::operator=(o);显式使用基类的复制赋值运算符,完成基类成员的深度复制,*this是隐藏调用者
/*#2*/或者这样this->Base::operator=(o);
/*#3*/*this = o;绝对不能这样做,因为隐式调用了子类的复制赋值运算符,无限递归!!!
sub_str = new char[std::strlen(o.sub_str)+1];
std::strcpy(sub_str,o.sub_str);
}
return *this;
}
#1和#2选其一就行,绝对不能选#3的代码
(Ⅲ)如何定义派生类析构函数
在析构函数里面delete派生类里面的动态内存即可,然后派生类的析构函数会自动调用基类的析构函数
,一般来说,基类的析构函数只要也有delete基类的动态内存,就没有任何问题了
但是要注意:和构造函数的调用顺序不同,析构函数是先调用派生类的,再调用基类的析构函数!!
Base::~Base()
{
delete[] str;
}
Sub::~Sub()
{
delete[] sub_str;
隐式执行基类析构函数
}