内部类 (Inner Class)
目的
-
不用通过量重继承就能够实现多套接口,同时可以自然地向上转换(Up-casting)。
-
在单个抽象下提供相同接口的多个实现。
别名
动机
两个独立类库通过不同的接口提供的虚函数签名可能冲突,如果这时候需要同时实现这两个函数就会出现问题。示例以下:
class Base1 { public: virtual int open (int) = 0; ~Base1() {} };
class Base2 { public: virtual int open (int) = 0; ~Base2() {} };
class Derived : public Base1, public Base2
{ public: virtual int open (int i)
{ return 0;
} ~Derived () {}
};
内部类惯用法就是用来解决这个问题。
解决方案及示例
依然是上面的例子,两个基类不用修改,改用以下方式实现子类:
#include class Base1 { public: virtual int open (int) = 0; ~Base1() {} };
class Base2 { public: virtual int open (int) = 0; ~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; } operator Base2&() { return base2_obj; } }; 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; std::cout << base2_open(d) << std::endl; }
附个类图便于理解:
这里的类Derived其实不是子类,而是通过内部的两个嵌套类实现不同的接口,再桥接回到自己定义的两个实现的函数: base1_open及base2_open。两个嵌套类不会同享继随关系,通过Derived类提供的两个转换操作符可以实现Derived转换到任意的基类。另外两个内部类对象也免去了额外的生命周期管理,它们的生命周期与Derived对象1致。
已知的利用
译注:
Inner Class的概念来自于Java, 其本特点是嵌套类通过友元的方式可使用外部类的私有成员变量和成员函数,从而支持更强的交互。而且通常这个内部类需要是私有的。
以Chromium网络模块的Http Cache为例:
这是1个简单的例子,并没有多重继承。更多的是强调了封装和信息隐藏(HttpCache::Transaction是HttpCache内私有的类)的OO特性。
相干的惯用法
-
Interface Class
-
Capability Query
-
Thinking in C++ Vol 2 - Practical Programming ― by Bruce Eckel.