面试题 48,不能被继承的类

C#的话,第一反应 sealed;Java的话第一反应 final;C++没这些关键字,毫无疑问,第一反应:把构造函数设为私有。当然,为了这个类本身依然能被实例化,我们需要提供另一个函数来构建实例。有点像单例模式,当然这里没有类是否已经存在的判断。
代码:
Class SealedClass{ public: static SealedClass* CreateInstance(){ return new SealedClass() }; private: SealedClass(); ~SealedClass(); }
书上代码:
class SealedClass1 { public: static SealedClass1* GetInstance() { return new SealedClass1(); } static void DeleteInstance( SealedClass1* pInstance) { delete pInstance; } private: SealedClass1() {} ~SealedClass1() {} };
当然这种解法的弊端显而易见:这个本身不能用new 来创建实例了。
书上提供了我没看懂的解法二。。。
template <typename T> class MakeSealed { friend T; private: MakeSealed() {} ~MakeSealed() {} }; class SealedClass2 : virtual public MakeSealed<SealedClass2> { public: SealedClass2() {} ~SealedClass2() {} }; // 如果试图从SealedClass1继承出新的类型, // 将会导致编译错误。 /* class Try2 : public SealedClass2 { public: Try2() {} ~Try2() {} }; */
我们可以看到类SealdClass2继承自MakedSealed,而MakedSealed的构造函数竟然是私有的。解法二推翻了解法一的前提吗?
关键就在于“友元”,类SealdClass2是类MakedSealed的友元类型,从而依然可以调用MakedSealed的构造函数。
第二个关键:虚拟继承
因为类SealdClass2采用虚拟继承来继承自MakedSealed,那么对于SealdClass2的子类,他们的构造函数将不是调用其父类SealdClass2的构造函数,而是调用祖父类MakedSealed的构造函数,SealdClass2的子类不是MakedSealed的友元类型,所以会导致编译错误。
书上说这种解法在有的编译器上无法得到需要的结果。。。
------------------------------------------------
Felix原创,转载请注明出处,感谢博客园!
posted on 2014-03-11 10:58 Felix Fang 阅读(204) 评论(0) 收藏 举报
浙公网安备 33010602011771号