如果我们不亲自给类提供重载的赋值运算符,则编译器将提供默认的函数。默认版本仅仅提供逐个成员的赋值过程,与默认复制构造函数的功能类似;但是不要混淆默认复制构造函数与默认默认复制运算符。默认复制构造函数时通过声明已现有同类对象进行初始化的,或者以传值方式给函数传递对象而被调用。反之,默认赋值运算符是在赋值语句的左边和右边是同类对象时被调用的。
对于CBox类来说,
class CBox
{
public:
CBox( double lv=1.0, double wv=1.0, double hv=1.0):length(lv),width(wv),height(hv)
{
cout << "Constructor called! "
<< endl;
}
private:
double length;
double width;
double height;
}
试用默认赋值运算符没有任何问题,但对于那些动态成员分配空间的类而言,我们就需要仔细考虑这些类的要求。如果我们在此类情形中不考虑赋值运算符,则程序中可能产生混乱。我们在看CMessage 类
class CMessage
{
public:
void show_it( ) const
{
cout << endl
<< pmessage;
}
CMessage( const char* text = "Default message! " )
{
pmessage = new char[ strlen(text)+1 ];
strcpy( pmessage,text );
}
~CMessage( );
private:
char* pmessage;
}
该类中有成员pmessage,指向字符串的指针。现在考虑默认赋值运算符的可能产生的结果。假设我们有该类的俩个实例motto_1 和 motto_2,
motto_2 = motto_1; // Use default assignment opreator
为该类使用默认赋值运算符的结果基本上与使用默认复制构造函数相同——灾难即将降临! 因为两个对象都有一个纸箱相同对象的指针,所以修改一个对象的字符串,受影响的是两个对象。另外一个问题是:当该类的实例之一被销毁时,其析构函数将释放该字符串占用的内存,因此另一个对象包含的指针指向可能被其他对象占用的内存。
我们可以使用自己的赋值运算符函数来修正上述问题:
// overloaded assignment operator for CMessage objects
CMessage& operator=( const CMessage& aMess )
{
// Release memory for 1st operand
delete[] pmessage;
pmessage = new char[ strlen(aMess.pmessage) + 1 ] ;
// Copy 2nd operand string to 1st
strcpy( this->pmessage, aMess.pmessage );
//Return a reference to 1st operand
return *this;
}