剑指offer 6.5 发散思维 - 不能被继承的类

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

题目:用C++设计一个不能被继承的类


C#中定义了sealed,被sealed修饰的类不能被继承

Java中被final修饰的类不能被继承。

C++中没有类似的定义,需要自己实现。

方案一:

在C++中,子类的构造函数会自动调用父类的构造函数。同样,子类的析构函数也会自动调用父类的析构函数。要想一个类不能被继承,只要把他的析构函数和构造函数都定义为私有函数,那么,当一个类试图去继承他的时候,必然会由于试图调用析构函数、构造函数而导致编译错误。

当一个类的构造函数和析构函数都定义为私有的之后,就无法得到这个类的实例,故还需要在类中额外定义一个静态函数来创建和释放该类的实例。

///
// Define a class which can't be derived from
///
class FinalClass1
{
public:
      static FinalClass1* GetInstance()
      {
            return new FinalClass1();
      }
 
      static void DeleteInstance( FinalClass1* pInstance)
      {
            delete pInstance;
            pInstance = 0;
      }
 
private:
      FinalClass1() {}
      ~FinalClass1() {}
};

使用这个类,只能值得类在堆上的实例,而得不到在栈上的实例。

方案二:

利用虚继承

template <typename T> class MakeFinal
{
      friend T;
 
private:
      MakeFinal() {}
      ~MakeFinal() {}
};
 
class FinalClass2 : virtual public MakeFinal<FinalClass2>
{
public:
      FinalClass2() {}
      ~FinalClass2() {}
};

FinalClass2 这个类的实例,可以在栈上、也可以在堆上创建实例。尽管类MakeFinal<FinalClass2>的构造函数和析构函数都是私有的,但由于类FinalClass2是它的友元函数,因此在FinalClass2中调用MakeFinal<FinalClass2>的构造函数和析构函数都不会造成编译错误。

但当我们试图从FinalClass2继承一个类并创建它的实例时,却不同通过编译。


class Try : public FinalClass2
{
public:
      Try() {}
      ~Try() {}
};
 
Try temp;

由于类FinalClass2是从类MakeFinal<FinalClass2>虚继承过来的,在调用Try的构造函数的时候,会直接跳过FinalClass2而直接调用MakeFinal<FinalClass2>的构造函数。非常遗憾的是,Try不是MakeFinal<FinalClass2>的友元,因此不能调用其私有的构造函数。

基于上面的分析,试图从FinalClass2继承的类,一旦实例化,都会导致编译错误,因此是FinalClass2不能被继承。这就满足了我们设计要求。

:方法二可移植性不好,虽然sealedClass2在virtual studio 中能够编译,但由于GCC中对friend的要求不同于virtual studio,

目前在最新的GCC中还不支持模板参数类型作为友元类型。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值