如果在派生類中要重載派生類的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);
所以我個人覺得,如果一個基類有很多個派生類的,而派生類中又重載了派生類本身的賦值操作符的時候,則基類中最好不要去重載賦值操作符,不如直接用函數去賦值。正如所說那樣,運算符重載只是為了一種語法上的方便,是另外一種函數調用方式,如果不能帶來方便,就沒必要了,還不如直接用函數去代替。
.............敬請指點..................