更多 C++ 慣用法/內部類
外觀
- 在沒有多重繼承的情況下實現多個介面,並提供自然的外觀向上轉換。
- 在單個抽象中提供同一介面的多種實現。
兩個獨立類庫提供的兩個獨立介面中的虛擬函式簽名可能發生衝突。當一個類必須根據您考慮的介面以不同的方式實現這兩個衝突函式時,這尤其是一個問題。例如,
class Base1 /// Provided by Moon
{
public:
virtual int open (int) = 0;
/* virtual */ ~Base1() {} // No polymorphic deletion allowed
};
class Base2 /// Provided by Jupitor
{
public:
virtual int open (int) = 0;
/* virtual */ ~Base2() {} // No polymorphic deletion allowed
};
class Derived : public Base1, public Base2
{
public:
virtual int open (int i)
{
// Call from which base class?
return 0;
}
/* virtual */ ~Derived () {}
};
內部類慣用法可以幫助解決此問題。
保持介面類 Base1 和 Base2 不變,我們可以如下實現 Derived 類。
#include <iostream>
class Base1 /// Provided by Moon
{
public:
virtual int open() = 0;
/* virtual */ ~Base1() {} // No polymorphic deletion allowed
};
class Base2 /// Provided by Jupitor
{
public:
virtual int open() = 0;
/* virtual */ ~Base2() {} // No polymorphic deletion allowed
};
class Derived // Note no inheritance
{
class Base1_Impl;
friend class Base1_Impl;
class Base1_Impl : public Base1 // Note public inheritance
{
public:
Base1_Impl(Derived* p) : parent_(p) {}
int open() override { return parent_->base1_open(); }
private:
Derived* parent_;
} base1_obj; // Note member object here.
class Base2_Impl;
friend class Base2_Impl;
class Base2_Impl : public Base2 // Note public inheritance
{
public:
Base2_Impl(Derived* p) : parent_(p) {}
int open() override { return parent_->base2_open(); }
private:
Derived* parent_;
} base2_obj; // Note member object here
int base1_open() { return 111; } /// implement
int base2_open() { return 222; } /// implement
public:
Derived() : base1_obj(this), base2_obj(this) {}
Derived(Derived const&) : base1_obj(this), base2_obj(this) {}
Derived(Derived&&) : base1_obj(this), base2_obj(this) {}
Derived& operator=(Derived const&) { return *this; }
Derived& operator=(Derived&&) { return *this; }
operator Base1&() { return base1_obj; } /// convert to Base1&
operator Base2&() { return base2_obj; } /// convert to Base2&
}; /// class Derived
int base1_open(Base1& b1) { return b1.open(); }
int base2_open(Base2& b2) { return b2.open(); }
int main(void) {
Derived d;
std::cout << base1_open(d) << std::endl; // Like upcasting in inheritance.
std::cout << base2_open(d) << std::endl; // Like upcasting in inheritance.
}
請注意 Derived 類中轉換運算子的使用。(Derived 類實際上不是派生類!)轉換運算子允許將 Derived 轉換為 Base1,即使它們本身沒有共享繼承關係!使用成員物件 base1_obj 和 base2_obj 消除了對物件生命週期的擔憂。成員物件的生命週期與 Derived 物件的生命週期相同。
C++ 程式設計思想 卷 2 - 實用程式設計 --- 由 Bruce Eckel 撰寫。