假设baseDMA
是基类,hasDMA
是由baseDMA
得到的派生类。
假设基类baseDMA
的赋值运算符有如下形式:
baseDMA & baseDMA::operator=(const baseDMA & rs)
{
if (this == &rs)
return *this;
delete [] label;
label = new char[std::strlen(rs.label) + 1];
std::strcpy(label, rs.label);
rating = rs.rating;
return *this;
}
当需要为派生类hasDMA
定义一个赋值运算符时,形式如下:
hasDMA & hasDMA::operator=(const hasDMA & hs)
{
if (this == &hs)
return *this;
baseDMA::operator=(hs); // copy base portion
delete [] style; // prepare for new style
style = new char[std::strlen(hs.style) + 1];
std::strcpy(style, hs.style);
return *this;
}
在这里有一句看起来比较奇怪的语句:
baseDMA::operator=(hs);
所以,这究竟是什么意思呢?
由于hasDMA
是由baseDMA
得到的派生类,因此hasDMA::operator=
作为hasDMA
的方法,不能够直接访问baseDMA
的private数据。因此,派生类赋值重载会调用基类赋值,而这句奇怪的语句就是完成了调用基类赋值的工作。
注意:虽然基类的赋值运算符定义了返回值,但是调用的时候可以不使用返回值。如果在此处添加返回值(即多了一个=),那么就会产生额外的递归,导致程序陷入死循环。
其实下面的语句更为直观,也能表达这种意思,而且还省去了对style
赋值的语句:
*this = hs;
但是当调用这个语句时,编译器会调用hasDMA::operator=(hs)
,从而形成递归调用,导致程序陷入死循环。
结论:
- 在定义派生类的赋值运算符时,使用函数表示法可以使得赋值运算符被正确调用。
- 由于派生类不能直接访问基类的数据成员,因此往往需要使用基类赋值运算符来对基类部分进行赋值,剩下派生类新定义的数据成员部分再另外赋值。
- 往往在需要使用动态内存分配时才会需要自己定义赋值运算符。