17 More Effective C++—條款25(建構函式與非成員函式的虛化)
阿新 • • 發佈:2018-12-26
1 建構函式的虛化
1 構造虛擬函式
建構函式與類的名稱相同,因此,此處所指的虛化,並非讓建構函式變成虛擬函式,而是讓其具有類似虛擬函式的行為:
當條件不同時,不同的物件會被創建出來。
下面的程式碼展示了“虛建構函式”的應用。
class Base { } class Derive1 : public Base { } class Derive2: public Base { } Base* constructObject(std::istream& inStream) { Base* obj; if (/*condition0*/) { // create Base's object } else if (/*condition1*/) { // create Derive1's object; } else { // create Derive2's object } return obj; }
2 “虛複製建構函式”
如下程式碼所示。C++11中,虛擬函式允許返回型別不同,因此,Base, Derive1, Derive2三個型別的clone可以看作時override。這樣,每次呼叫clone函式,可以根據相應的物件,來進行復制。
class Base { public: virtual Base* clone() const; } class Derive1 : public Base { public: virtual Derive1* clone() const; } class Derive2 : public Base { public: virtual Derive2* clone() const; } void func() { std::vector<Base*> objList, targetList; for (int idx = 0; idx < objList.size(); ++idx) { targetList.push_back(objList->clone()); // 關鍵程式碼 } }
clone()通常直接呼叫函式的“複製建構函式”。程式碼如下:
Base* Base::clone()
{
return new Base(*this);
}
Derive1* Derive1::clone()
{
return new Derive1(*this);
}
...
總結:通過增加一層虛擬函式clone,我們實現了,根據不同型別來進行復制構造的操作,從而實現多型。
2 非成員函式地虛化
流操作“<<”用於輸出記憶體中的內容。現在,我希望,操作符“<<”能根據不同型別來輸出內容。下面將討論兩種情況。
1 型別之間沒有關係
比如,我手頭有3個類,定義如下。他們之間沒有任何關係,那麼就需要針對這三個型別,過載"<<"。這樣,就可以實現虛化——針對不同型別,能都在執行期間動態調整。
class My1 {
}
class My2 {
}
class My3 {
}
std::ostream operator << (std::ostream& out, const My1& obj);
std::ostream operator << (std::ostream& out, const My2& obj);
std::ostream operator << (std::ostream& out, const My3& obj);
實際上,這與虛擬函式的定義有一定差別。虛擬函式需要限定如下幾個條件。因此,我們引出第二種情況。
1 “虛”行為,針對的是有繼承關係的類。
2 表面上看是基類的行為,實際上可能是子類的行為。
3 基類和子類的行為不完全相同。
2 非成員函式的虛行為
現在有若干水果類,繼承與定義關係如下。那麼,我們需要根據不同的水果型別,來輸出其名字。那麼就可以利用虛擬函式。
class Fruit {
pulic:
virtual std::string print();
}
class Apple : public Fruit {
public:
virtual std::string print();
}
class BananaApple : public Apple {
public:
virtual std::string print();
}
std::ostream operator << (std::ostream& out, const Fruit& obj)
{
obj.print(); // 根據多型,上面定義的三個類中的print都可以被呼叫
}
上面過載的<<,展示了我們可以傳入基類,然後利用基類的多型性,從而實現非成員函式的多型性。