如果在派生类中要重载派生类的operator = ,那么在基类中一般不要重载operator = ,因为这样会带来很多麻烦.
定义了两个类:
class CBase
{
public:
CBase()
{
cout<<"CBase constructing ..."<<endl;
}
virtual ~CBase()
{
cout<<"CBase destructing ..."<<endl;
}
public:
CBase & operator=(const CBase & ent)
{
cout<<"CBase operator = ... "<<endl;
return *this;
}
};
class CDerive: public CBase
{
public:
CDerive()
{
cout<<"CDerive constructing
}
~CDerive()
{
cout<<"CDerive destructing ..."<<endl;
}
public:
CDerive & operator=(const CDerive & ent)
{
cout<<"CDerive operator = ... "<<endl;
return *this;
}
}
定义如下操作:
CBase * b1 = new CDerive();
CBase * b2 = new CDerive();
(*b1) = (*b2);
可以看到其输出为:
CBase constructing ...
CDerive constructing ...
CBase constructing ...
CDerive constructing ...
CBase operator = ...
CDerive destructing ...
CBase destructing ...
CDerive destructing ...
CBase destructing
而实际上,操作(*b1) = (*b2)是想把b1,b2实际所指类型的两个对象之间进行赋值,但是它只是调用了基类的赋值操作,没有执行其本身派生类的赋值操作。
发现有两种方法可以解决这个问题,如果能够知道基类指针实际所指的是哪个派生类的的对象,直接类型转换就可以了:
(*((CDerive*)b1)) = (*((CDerive*)b2));
这样可以发现输出了:CDerive operator = ... 。但是当要定义基类的指针的时候,往往隐藏了具体的派生类,即往往不知道指针到底实现的是哪个派生类,所以这种方法有很多局限性。
这时候可以采用第二种方法,即在派生类中重载基类的赋值操作符,即首先把基类的operator=定义为virtual operator=,再在派生类中重载这个,如:
CBase & operator=(const CBase & ent)
{
const CDerive * p = reinterpret_cast<const CDerive *>(&ent);
return operator=((*p));
}
好的,当再执行 (*b1) = (*b2) 的时候就可以看到输出:CDerive operator = ... 。
在此发现在派生类中重载派生类的operator =的时候,如果在基类中也重载operator = ,这样会带来很多麻烦,可能会丢失很多也许不想丢失的数据。
同样,依次还存在问题:
CBase * b1 = new CDerive();
CDervie * d1 = new CDerive();
(*b1) = (*d1);
CBase * b2 = new CBase ();
CDervie * d2 = new CDerive();
(*b2) = (*d2);
所以我个人觉得,如果一个基类有很多个派生类的,而派生类中又重载了派生类本身的赋值操作符的时候,则基类中最好不要去重载赋值操作符,不如直接用函数去赋值。正如所说那样,运算符重载只是为了一种语法上的方便,是另外一种函数调用方式,如果不能带来方便,就没必要了,还不如直接用函数去代替。
.............敬请指点..................