翻译:C++的内部类机制
节选自:Thinking in C++ Vol. 2 - Practical Programming
http://www.linuxtopia.org/online_books/programming_books/c++_practical_programming/c++_practical_programming_254.html
……我们从Java借用来一种解决方案,在C++的内嵌类的基础上向前进一步。Java中内置了“内部类”(Inner Class)的机制,与C++中的内嵌类(nested class)相似,但却能够能访问外围类的非静态成员,因为它可以隐含地使用其创建者(外围类的一个实例)的this的指针。
如果要在C++中实现内部类,我们就必需显式地获得和使用外围类对象的指针。以下为示例:
//: C10:InnerClassIdiom.cpp
// Example of the "inner class" idiom.
#include #include using namespace std; class Poingable { public: virtual void poing() = 0; }; void callPoing(Poingable& p) { p.poing(); } class Bingable { public: virtual void bing() = 0; }; void callBing(Bingable& b) { b.bing(); } class Outer { string name; // Define one inner class: class Inner1; friend class Outer::Inner1; class Inner1 : public Poingable { Outer* parent; public: Inner1(Outer* p) : parent(p) {} void poing() { cout << "poing called for " << parent->name << endl; // Accesses data in the outer class object } } inner1; // Define a second inner class: class Inner2; friend class Outer::Inner2; class Inner2 : public Bingable { Outer* parent; public: Inner2(Outer* p) : parent(p) {} void bing() { cout << "bing called for " << parent->name << endl; } } inner2; public: Outer(const string& nm) : name(nm), inner1(this), inner2(this) {} // Return reference to interfaces // implemented by the inner classes: operator Poingable&() { return inner1; } operator Bingable&() { return inner2; } }; int main() { Outer x("Ping Pong"); // Like upcasting to multiple base types!: callPoing(x); callBing(x); } ///:~
上面这个例子有意使用了最简单的语法来说明这个机制(以后能看到一个实际的应用)。从Poingable和Bingable接口定义开始,它们各有一个成员函数。由callPoing( )和callBing( )提供的服务仅要求所传入的对象分别具备Poingable和Bingable接口,以最大限度地保持这两个函数的灵活性。请注意两个接口都没有虚拟的析构函数,目的是防止通过接口进行析构。
Outer构造器中包含了一些私有数据(name),我们希望它同时提供Poingable接口和Bingable接口以便能够在callPoing( )和callBing( )中使用它。(这里当然我们完全可以简单地使用多重继承,但这只是个为了说明而有意简化过的例子)。为了让Outer类在不继承Poingable的情况下提供Poingable接口,我们使用了内部类机制。
首先,class Inner的声明指出我们在其他地方以这个名字定义了内嵌类,这样接下来就可以将这个内嵌类定义为友元,以便在内嵌类中可以自由地访问外部类的成员。然后,我们就可以定义内嵌类了,注意它保存了创建者的指针(Outer类),并在构造函数中初始化了这个指针。最后,我们实现了Poingable的poing( ) 函数。对另一个实现Bingable接口的内部类,流程是一样的。两个内部类都只创建了一个私有实例,由Outer构造器完成初始化。创建成员对象后,返回的是对它们的引用这样对象生存期的问题就被解决了。
请注意,两个内部类的定义都是私有的,实际上客户端代码根本访问不到其具体实现,因为访问函数operator Poingable&( )和operator Bingable&( )返回的是基类的引用,而不是对实例的引用。事实上,由于两个内部类都是私有的, 客户端程序甚至无法将该引用向下转换到实现类,这样,接口和实现之间就实现了完全隔离。
定义自动的类型转换函数operator Poingable&( )和operator Bingable&( )使整个机制能更加灵活。在main( )中可以看到,语法上仿佛Outer 是从 Poingable和Bingable多重继承而来,但区别在于,这种转换是单向的,可以向上转换为 Poingable和Bingable,却不能向下转回Outer
来自:http://linwx1978.blog.163.com/blog/static/1504106920099145846111/