[OOD-More C++ Idioms] 內部類 (Inner Class)
內部類 (Inner Class)
目的
- 不用通過多重繼承就可以實現多套介面,同時可以自然地向上轉換(Up-casting)。
- 在單個抽象下提供相同介面的多個實現。
別名
動機
兩個獨立類庫通過不同的介面提供的虛擬函式簽名可能衝突,如果這時需要同時實現這兩個函式就會出現問題。示例如下:
class Base1 /// 來自月球
{
public:
virtual int open (int) = 0;
/* virtual */ ~Base1() {} // 不允許多型的解構函式
};
class Base2 /// 來自木星
{
public:
virtual int open (int) = 0;
/* virtual */ ~Base2() {} // 不允許多型的解構函式
};
class Derived : public Base1, public Base2
{
public:
virtual int open (int i)
{
// Wow! 到底來自哪裡?
return 0;
}
/* virtual */ ~Derived () {}
};
內部類慣用法就是用來解決這個問題。
解決方案及示例
仍然是上面的例子,兩個基類不用修改,改用如下方式實現子類:
#include <iostream>
class Base1 /// 來自月球
{
public:
virtual int open (int) = 0;
/* virtual */ ~Base1() {} // 不允許多型的解構函式
};
class Base2 /// 來自木星
{
public:
virtual int open (int) = 0;
/* virtual */ ~Base2() {} // 不允許多型的解構函式
};
class Derived // 注意沒有繼承
{
class Base1_Impl;
friend class Base1_Impl; // 注意宣告友元
class Base1_Impl : public Base1 // 注意是公共繼承
{
public:
Base1_Impl(Derived* p) : parent_(p) {}
int open() override { return parent_->base1_open(); }
private:
Derived* parent_;
} base1_obj; // 注意成員變數.
class Base2_Impl;
friend class Base2_Impl; // 注意宣告友元
class Base2_Impl : public Base2 // 公共繼承
{
public:
Base2_Impl(Derived* p) : parent_(p) {}
int open() override { return parent_->base2_open(); }
private:
Derived* parent_;
} base2_obj; // 成員變數
int base1_open() { return 111; } /// 實現
int base2_open() { return 222; } /// 實現
public:
Derived() : base1_obj(this), base2_obj(this) {}
operator Base1&() { return base1_obj; } /// 轉到Base1&
operator Base2&() { return base2_obj; } /// 轉到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並不是子類,而是通過內部的兩個巢狀類實現不同的介面,再橋接回到自己定義的兩個實現的函式: base1_open及base2_open。兩個巢狀類不會共享繼隨關係,通過Derived類提供的兩個轉換操作符可以實現Derived轉換到任意的基類。另外兩個內部類物件也免去了額外的生命週期管理,它們的生命週期與Derived物件一致。
已知的應用
譯註:
Inner Class的概念來自於Java, 其本特徵是巢狀類通過友元的方式可以使用外部類的私有成員變數和成員函式,從而支援更強的互動。而且通常這個內部類需要是私有的。
以Chromium網路模組的Http Cache為例:
這是一個簡單的例子,並沒有多重繼承。更多的是強調了封裝和資訊隱藏(HttpCache::Transaction是HttpCache內私有的類)的OO特性。
相關的慣用法
- Interface Class
- Capability Query
參考
- Thinking in C++ Vol 2 - Practical Programming — by Bruce Eckel.
相關文章
- [OOD-More C++ Idioms] 寫時拷貝 (Copy on Write)C++
- [OOD-More C++ Idioms] 律師與委託人 (Attorney-Client)C++client
- java內部類,區域性內部類,靜態內部類,匿名內部類Java
- java之內部類(InnerClass)----非靜態內部類、靜態內部類、區域性內部類、匿名內部類Java
- 10-Java內部類——成員內部類、區域性內部類、匿名內部類Java
- java內部類之成員內部類之匿名內部類Java
- java內部類之成員內部類之區域性內部類Java
- Java內部類詳解--匿名內部類Java
- java內部類之成員內部類Java
- 內部類
- Java內部類詳解-- 成員內部類Java
- java內部類,為什麼需要內部類?Java
- Java內部類和匿名內部類的用法Java
- Java學習筆記-Day21 Java System類、Class類、內部類、異常處理Java筆記
- Java中的巢狀類、內部類、靜態內部類Java巢狀
- Java內部類詳解--區域性內部類Java
- java內部類之成員內部類例項Java
- Java 內部類Java
- 匿名內部類
- Java內部類Java
- Java基礎內部類4-內部類進階Java
- Java基礎10---包、內部類、匿名內部類Java
- Java中的匿名內部類及內部類的二三事Java
- 靜態內部類和非靜態內部類區別
- Java類與匿名內部類Java
- 10、Java——內部類Java
- 泛型,內部類泛型
- java內部類案例Java
- 搞懂 JAVA 內部類Java
- Java--內部類Java
- java的內部類Java
- 內部類總結
- 匿名內部類理解
- 內部類,Object,字串Object字串
- C++中的抽象基類(Abstract Base Class)C++抽象
- 淺談java內部類Java
- Java-InnerClass內部類Java
- Java內部類詳解Java