59.不能被继承的类(语法)。
题目:用C++设计一个不能被继承的类。
分析:这是Adobe公司2007年校园招聘的最新笔试题。
这道题除了考察应聘者的C++基本功底外,还能考察反应能力,是一道很好的题目。
思路:
这道题,初看起来比较奇葩。对于我这种新手来说真的是这样的。当我第一眼看到这个题目的时候,基本上是没有思路的,后来我想了下,貌似在Effective c++上看到过类似的说明,说是如果不想用编译器为你自动生成的一些函数,就要明确的指明出来。它上面说的方法就是将这些个函数声明为私有函数。于是,我就想到,如果将某个类的构造函数和析构函数都声明为私有的话,那么如果有新的类对其进行继承,在声明新的变量时,由于父类的构造函数无法调用,编译器就会报错。这是非常好的 ,因为让错误出现在编译阶段远远要好于让其出现在运行时。。。于是,说干就干,只要简单的将构造函数和析构函数都声明为私有就行了。
但是,菜鸟就是菜鸟,觉得这么一道题难道就是这样就解决了?不自信的又查看了july大神的解答。得到了这么一个参考:
// Define a class which can't be derived from template <typename T> class MakeFinal { friend T; private: MakeFinal() {} ~MakeFinal() {} };
class FinalClass2 : virtual public MakeFinal<FinalClass2> { public: FinalClass2() {} ~FinalClass2() {} };于是乎当我们定义这么一个子类时,会编译出错:
class Try : public FinalClass2 { public: Try() {} ~Try() {} };这个类使用起来和一般的类没有区别,可以在栈上、也可以在堆上创建实例。尽管类MakeFinal<FinalClass2>的构造函数和析构函数都是私有的,但由于类FinalClass2是它的友元函数,因此在FinalClass2中调用MakeFinal<FinalClass2>的构造函数和析构函数都 不会造成编译错误。 但当我们试图从FinalClass2继承一个类并创建它的实例时,却不同通过编译。由于类FinalClass2是从类MakeFinal<FinalClass2>虚继承过来的,在调用Try的构造函数的时候,会直接跳过FinalClass2而直接调用MakeFinal<FinalClass2>的构造函数。非常遗憾的是,Try不是MakeFinal<FinalClass2>的友元,因此不能调用其私有的构造函数。 基于上面的分析,试图从FinalClass2继承的类,一旦实例化,都会导致编译错误,因此是FinalClass2不能被继承。这就满足了我们设计要求。