惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
S
SegmentFault 最新的问题
V
Visual Studio Blog
人人都是产品经理
人人都是产品经理
阮一峰的网络日志
阮一峰的网络日志
腾讯CDC
Stack Overflow Blog
Stack Overflow Blog
博客园 - 【当耐特】
Recent Announcements
Recent Announcements
I
InfoQ
U
Unit 42
博客园_首页
GbyAI
GbyAI
Hugging Face - Blog
Hugging Face - Blog
罗磊的独立博客
博客园 - 叶小钗
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
D
DataBreaches.Net
aimingoo的专栏
aimingoo的专栏
月光博客
月光博客
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 聂微东
T
Tailwind CSS Blog
量子位

博客园 - pipicfan

unity性能优化之Drawcall优化 谈谈我是如何面试技术人员的 Shader中颜色的加法和乘法的区别 unity性能优化-实际开发中需要注意的点 向字符数组中插入一个字符 cocos2dx 新手引导 c++面试题 c++实现委托 屁屁桌面管理 War3Tool dota改键v3.3版 魔兽全屏改键工具 很犀利的错误 关于vs2003环境支持win7 的 IP设置 自己的毕业设计windows管理软件 很容易犯的错误 敏感词过滤和谐社会1.0版 宿舍计费系统105加强版 自己实现string类 (转)字符编码笔记:ASCII,Unicode和UTF-8
用C++ 设计一个不能被继承的类
pipicfan · 2012-12-04 · via 博客园 - pipicfan


分析:这是Adobe 公司2007 年校园招聘的最新笔试题。这道题除了考察应聘者的C++ 基本功底外,还能考察反应能力,是一道很好的题目。

在Java 中定义了关键字final ,被final 修饰的类不能被继承。但在C++ 中没有final 这个关键字,要实现这个要求还是需要花费一些精力。

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

可是这个类的构造函数和析构函数都是私有函数了,我们怎样才能得到该类的实例呢?这难不倒我们,我们可以通过定义静态来创建和释放类的实例。基于这个思路,我们可以写出如下的代码:

///////////////////////////////////////////////////////////////////////

// Define a class which can't be derived from

///////////////////////////////////////////////////////////////////////

class FinalClass1

{

public :

      static FinalClass1GetInstance()

      {

            return new FinalClass1;

      }

      static void DeleteInstanceFinalClass1pInstance)

      {

            delete pInstance;

            pInstance = 0;

      }

private :

      FinalClass1() {}

      ~FinalClass1() {}

};

这个类是不能被继承,但在总觉得它和一般的类有些不一样,使用起来也有点不方便。比如,我们只能得到位于堆上的实例,而得不到位于栈上实例。

能不能实现一个和一般类除了不能被继承之外其他用法都一样的类呢?办法总是有的,不过需要一些技巧。请看如下代码:

///////////////////////////////////////////////////////////////////////

// Define a class which can't be derived from

///////////////////////////////////////////////////////////////////////

template <typename Tclass MakeFinal

{

      friend T;

private :

      MakeFinal() {}

      ~MakeFinal() {}

};

class FinalClass2 : virtual public MakeFinal<FinalClass2>

{

public :

      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 不能被继承。这就满足了我们设计要求。