《剑指Offer》学习笔记--面试题48:不能被继承的类
2015-05-15 10:46
295 查看
题目:用C++设计一个不能被继承的类
在c#中定义了关键字sealed,被sealed修饰的类不能被继承。在Java中同样也有关键字final表示一个类型不能被继承。在C++中没有类似于sealed和final的关键字,我们只有自己来实现。
常规的解法:把构造函数设为私有函数
很多人都能够想到,在C++中子类的构造函数会自动调用父类的构造函数,子类的析构函数也会自动调用父类的析构函数。要想一个类不能被继承,我们只要把它的构造函数和析构函数都定义为私有函数。那么当一个类视图从它那继承的时候,必然会由于调用构造函数、析构函数而导致编译错误。
可是这个类型的构造函数和析构函数都是私有函数,我们怎样才能得到该类型的实例呢?我们可以通过定义公有的静态函数来创建和释放类的实例,基于这个思路,我们可以写出如下代码:
这个类是不能被继承的,但总觉得它和普通的类型有些不一样,使用起来有点不方便。比如我们只能得到位于堆上的实例,而得不到位于栈上的实例。
新奇的解法:利用虚拟继承,能给面试官留下很好的印象
能不能实现一个与一般的类型相比除了不能被继承之外其他用法都一样的类型呢?办法还是有的,不过需要一定的技巧。请看如下代码:
但当我们试图从SealedClass2中继承一个类并创建它的实例的时候,却不能通过编译。比如我们从SealedClass2中继承出类型Try:
通过上面分析,我们发现从SealedClass2继承的类,一旦实例化就会导致编译错误,因此SealedClass2不能被继承,这也就满足了题目的要求。
在c#中定义了关键字sealed,被sealed修饰的类不能被继承。在Java中同样也有关键字final表示一个类型不能被继承。在C++中没有类似于sealed和final的关键字,我们只有自己来实现。
常规的解法:把构造函数设为私有函数
很多人都能够想到,在C++中子类的构造函数会自动调用父类的构造函数,子类的析构函数也会自动调用父类的析构函数。要想一个类不能被继承,我们只要把它的构造函数和析构函数都定义为私有函数。那么当一个类视图从它那继承的时候,必然会由于调用构造函数、析构函数而导致编译错误。
可是这个类型的构造函数和析构函数都是私有函数,我们怎样才能得到该类型的实例呢?我们可以通过定义公有的静态函数来创建和释放类的实例,基于这个思路,我们可以写出如下代码:
class SealedClass1 { public: static SealedClass* GetInstance() { return new SealedClass1(); } static void DeleteInstance(SealedClass1* pInstance) { delete pInstance; } private: SealedClass1(){} ~SealedClass1(){} };
这个类是不能被继承的,但总觉得它和普通的类型有些不一样,使用起来有点不方便。比如我们只能得到位于堆上的实例,而得不到位于栈上的实例。
新奇的解法:利用虚拟继承,能给面试官留下很好的印象
能不能实现一个与一般的类型相比除了不能被继承之外其他用法都一样的类型呢?办法还是有的,不过需要一定的技巧。请看如下代码:
template<typename T> class MakeSealed { friend T; private: MakeSealed(){} ~MakeSealed(){} }; class SealedClass2 : virtual public MakeSealed<SealedClass2> { public: SealedClass2(){} ~SealedClass2(){} };这个SealedClass2使用起来和一般的类型没有区别,我们可以在栈上、也可以在堆上创建实例。尽管类MakeSealed<SealedClass2>的构造函数和析构函数都是私有的,但由于类SealedClass2是它的友元类型,因此在SealedClass2中调用MakeSealed<SealedClass2>的构造函数和析构函数都不会引起编译错误。
但当我们试图从SealedClass2中继承一个类并创建它的实例的时候,却不能通过编译。比如我们从SealedClass2中继承出类型Try:
class Try : public SealedClass2 { public : Try(){} ~Try(){} };由于类SealedClass2是从类MakeSealed<SealedClass2>虚继承过来的,在调用Try的构造函数的时候,会跳过SealedClass2而直接调用MakeSealed<SealedClass2>的构造函数。非常遗憾的是,Try不是MakeSealed<SealedClass2>的友元类型,因此不能调用它的私有构造函数。
通过上面分析,我们发现从SealedClass2继承的类,一旦实例化就会导致编译错误,因此SealedClass2不能被继承,这也就满足了题目的要求。
相关文章推荐
- 剑指Offer面试题47不用加减乘除做加法(位运算),面试题48不能被继承的类(final)
- (剑指Offer)面试题48:不能被继承的类
- 剑指offer——面试题48:用C++设计一个不能被继承的类
- IOS学习笔记48--一些常见的IOS知识点+面试题
- 《剑指Offer》学习笔记--面试题13:在O(1)时间删除链表结点
- 面试题48:不能被继承的类
- 《剑指Offer》学习笔记--面试题55:字符流中第一个不重复的字符
- 《剑指Offer》学习笔记--面试题63:二叉搜索树的第k个结点
- 《剑指Offer》学习笔记--面试题14:调整数组顺序使奇数位于偶数前面
- 《剑指Offer》学习笔记--面试题18:树的子结构
- 《剑指Offer》学习笔记--面试题24:二叉搜索树的后序遍历
- 《剑指Offer》学习笔记--面试题26:复杂链表的复制
- 面试题48:用C++设计一个不能被继承的类
- 《剑指Offer》学习笔记--面试题46:求1+2+...+n
- 《剑指Offer》学习笔记--面试题4:替换空格
- 《剑指Offer》学习笔记--面试题27:二叉搜索树与双向链表
- 《剑指Offer》学习笔记--面试题38:数字在排序数组中出现的次数
- 《剑指Offer》学习笔记--面试题43:n个骰子的点数
- 剑指offer 面试题48 不能被继承的类
- 《剑指Offer》学习笔记--面试题53:正则表达式匹配