1、派生类不使用new:
此时不需要为派生类定义显式析构函数、复制构造函数和赋值运算符。
2、派生类使用new:
此时需要为派生类定义显式析构函数、复制构造函数和赋值运算符。
基类中使用了动态内存分配:
class baseDMA
{
private:
char * label;
int rating;
public:
baseDMA(const char * l="null", int r=-);
baseDMA(const baseDMA & rs);
virtual ~baseDMA();
baseDMA & operator=(const baseDMA & rs);
friend ostream & operator<<(ostream &os, const baseDMA &rs);
...
};
派生类也使用了new:
class hasDMA: public baseDMA
{
private:
char * style;
public:
...
};
1. 析构函数
派生类析构函数自动调用基类析构函数,故其自身的职责是对派生类构造函数执行工作的进行清理。因此,hasDMA析构函数必须释放指针style管理的内存,并依赖于baseDMA的析构函数来释放指针label管理的内存。
baseDMA::~baseDMA()
{
delete [] label;
}
hasDMA::~hasDMA()
{
delete [] sytle;
}
2. 复制构造函数
hasDMA复制构造函数只能访问hasDMA的数据,因此它必须调用baseDMA复制构造函数(通过成员初始化列表语法)来处理共享的baseDMA数据。
hasDMA::hasDMA(const hasDMA & hs) : baseDMA(hs)
{
style = new char[strlen(hs.style)+1];
strcpy(style,hs.style);
}
这里,成员初始化列表将一个hasDMA引用传递给baseDMA构造函数,基类引用可以指向派生类对象,实现了向上强制类型转换。1
3. 赋值运算符
hasDMA方法只能直接访问hasDMA的数据,它又不是构造函数,不能使用成员初始化列表语法,只能通过作用域解析运算符显式调用基类赋值运算符。
hasDMA & hasDMA::operator=(const hasDMA & hs)
{
if(this == &hs)
return *this;
baseDMA::operator=(hs); //作用域解析运算符显式调用基类赋值运算符
delete [] style;
style = new char[strlen(hs.style)+1];
strcpy(style,hs.style);
return *this;
}
4. 友元函数
作为hasDMA类的友元,该函数可以访问style成员,但它不是baseDMA类的友元,要使用baseDMA类的友元函数operator<<()。但友元不是成员函数,不能使用作用域解析运算符,必须使用强制类型转换。
ostream & operator<<(ostream & os, const hasDMA & hs)
{
os << (const baseDMA &)hs; //将参数const hasDMA&转换成const baseDMA&类型
os<<"Style: " << hs.style <<endl;
return os;
}