實際程式設計中,這意味著寫賦值運算子時,必須對物件的每乙個資料成員賦值:
template// 名字和指標相關聯的類的模板
class namedptr ;
template
namedptr& namedptr::operator=(const namedptr& rhs)
初寫這個類時當然很容易記住上面的原則,但同樣重要的是,當類裡增加新的資料成員時,也要記住更新賦值運算子函式。例如,打算公升級namedptr模板使得名字改變時附帶乙個時間標記,那就要增加乙個新的資料成員,同時需要更新建構函式和賦值運算子。但現實中,因為忙於公升級類的具體功能和增加新的成員函式等,這一點往往很容易被忘記。
當涉及到繼承時,情況就會更有趣,因為派生類的賦值運算子也必須處理它的基類成員的賦值!看看下面:
class base
private:
int x;
};class derived: public base
derived& operator=(const derived& rhs);
private:
int y;
};邏輯上說,derived的賦值運算子應該象這樣:
// erroneous assignment operator
derived& derived::operator=(const derived& rhs)
不幸的是,它是錯誤的,因為derived物件的base部分的資料成員x在賦值運算子中未受影響。例如,考慮下面的**段:
void assignmenttester()
請注意d1的base部分沒有被賦值操作改變。
解決這個問題最顯然的辦法是在derived::operator=中對x賦值。但這不合法,因為x是base的私有成員。所以必須在derived的賦值運算子裡顯式地對derived的base部分賦值。
也就是這麼做:
// 正確的賦值運算子
derived& derived::operator=(const derived& rhs)
這裡只是顯式地呼叫了base::operator=,這個呼叫和一般情況下的在成員函式中呼叫另外的成員函式一樣,以*this作為它的隱式左值。base::operator=將針對*this的base部分執行它所有該做的工作——正如你所想得到的那種效果。
但如果基類賦值運算子是編譯器生成的,有些編譯器會拒絕這種對於基類賦值運算子的呼叫(見條款45)。為了適應這種編譯器,必須這樣實現derived::operator=:
derived& derived::operator=(const derived& rhs)
這段怪異的**將*this強制轉換為base的引用,然後對其轉換結果賦值。這裡只是對derived物件的base部分賦值。還要注意的重要一點是,轉換的是base物件的引用,而不是base物件本身。如果將*this強制轉換為base物件,就要導致呼叫base的拷貝建構函式,建立出來的新物件(見條款m19)就成為了賦值的目標,而*this保持不變。這不是所想要的結果。
不管採用哪一種方法,在給derived物件的base部分賦值後,緊接著是derived本身的賦值,即對derived的所有資料成員賦值。
另乙個經常發生的和繼承有關的類似問題是在實現派生類的拷貝建構函式時。看看下面這個建構函式,其**和上面剛討論的類似:
class base
base(const base& rhs): x(rhs.x) {}
private:
int x;
};class derived: public base
derived(const derived& rhs) // 錯誤的拷貝
: y(rhs.y) {} // 建構函式
private:
int y;
};類derived展現了乙個在所有c++環境下都會產生的bug:當derived的拷貝建立時,沒有拷貝其基類部分。當然,這個derived物件的base部分還是建立了,但它是用base的預設建構函式建立的,成員x被初始化為0(預設建構函式的預設引數值),而沒有顧及被拷貝的物件的x值是多少!
為避免這個問題,derived的拷貝建構函式必須保證呼叫的是base的拷貝建構函式而不是base的預設建構函式。這很容易做,只要在derived的拷貝建構函式的成員初始化列表裡對base指定乙個初始化值:
class derived: public base
現在,當用乙個已有的同型別的物件來拷貝建立乙個derived物件時,它的base部分也將被拷貝了。
Effective C 經驗條款
高效c 4 必須返回物件時,別妄想返回其reference 這句話什麼意思呢?就是在乙個函式內,如果你需要這個函式返回乙個新的物件,那麼這個函式的返回值型別就不要定義成引用型別。就直接返回這個類型別。首先,我們知道在函式傳遞引數時,傳遞引用的好處,尤其是對那麼比較大的型別,但是對於內建型別和stl的...
effective c 條款總結
條款1 盡量用const 和inline 而不用 define 條款2 盡量用而不用 條款3 盡量用new delete 而不用malloc free 條款4 盡量使用c 風格注釋 條款5 對應的new和delete 都要採用相同的形式 條款6 析構函式裡對指標成員呼叫delete條款 條款7 預先...
Effective C 經驗條款
高效c 模板與泛型程式設計 在c 中模板體現的是編譯期多型,virtual體現的是執行期多型。關於typename的雙重含義 在宣告template引數時,不論使用keywordclass或typename,意義全然同樣。可是c 並不總是把class和typename視為等價。有時候必須使用type...