在Java 中定义了关键字final,被final修饰的类不能被继承。

首先想到的是在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 = ;
} private :
FinalClass1() {}
~FinalClass1() {}
};

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

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

 ///////////////////////////////////////////////////////////////////////
// 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() {}
};

这个类使用起来和一般的类没有区别,可以在栈上、也可以在堆上创建实例。尽管类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不能被继承。这就满足了设计要求。

C++11中已经有了final关键字:它的作用是指定类的虚函数不能被该类的继承类重写(override),或者是指定一个类成为一个不能被继承的类(final class)。

 struct A
{
virtual void foo() final;
}; struct B final : A
{
void foo(); // Error: foo cannot be overridden as it's final in A
}; struct C : B // Error: B is final
{
};
作者:阿凡卢
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

用C++设计一个不能被继承的类(转)的更多相关文章

  1. 用C++设计一个不能被继承的类(用私有构造函数+友元函数)

    题目:用C++设计一个不能被继承的类. 分析:这是Adobe公司2007年校园招聘的最新笔试题.这道题除了考察应聘者的C++基本功底外,还能考察反应能力,是一道很好的题目. 在Java中定义了关键字f ...

  2. 面试题48:用C++设计一个不能被继承的类

    解法一:把构造函数设为私有 将构造函数定义为私有,然后通过定义公有的静态函数来创建和释放类的实例. { public: static SealedClass1* GetInstance() { ret ...

  3. c++设计一个无法被继承的类

    要求是该类不能被继承,但是能够像正常的类一样使用.那么一下方法就不符合题目要求: 1.构造函数和析构函数设置为private.这样就不能定义一个类的实例 2.类似于singleton模式那样,定义一个 ...

  4. 用C++ 设计一个不能被继承的类

    http://blog.sina.com.cn/s/blog_69d9bff30100odlz.html 在Java 中定义了关键字final ,被final 修饰的类不能被继承.但在C++ 中没有f ...

  5. C++设计一个不能被继承的类

    1. 方法一 将构造函数和析构函数设置为私有函数,重新定义公有的静态函数来创建和释放类. #include "stdafx.h" #include <iostream> ...

  6. 探讨C++实现一个不可被继承的类

    C#和Java都提供了一种机制让一个类不能被继承,如C#中的sealed关键字和Java的final关键字,然而C++程序员就没这么好命了.不过C++也可以模拟出这种效果,原理基于:子类的构造函数会自 ...

  7. C++设计实现一个不能被继承的类

    C++不同于Java,Java中被final关键字修饰的类不能被继承,C++能实现不被继承的类,但是需要自己实现. 为了使类不被继承,最好的办法是使子类不能构造父类的部分,此时子类就无法实例化整个子类 ...

  8. 用C++实现一个不能被继承的类

    #include<iostream> using namespace std; class Gradpa { friend class Parent;//声明public或者private ...

  9. 用c++编写一个不能被继承的类(但是可以在类外部定义该类的对象)

    据我们知道,我们只要把类的构造函数和析构函数定义为private类型,那么就不能够在外部建立给类的对象,也就不能以给类为基类进行继承,因为如果继承,建立对象的时候将要调用基类的构造函数,但是因为为pr ...

随机推荐

  1. day03_13 多分支if语句及作业

    猜年龄升级版 age_of_princal = 56 guess_age = int( input("请输入您猜测的年龄") ) if guess_age == age_of_pr ...

  2. day03_08 变量的重新赋值02

    python自动回收垃圾内存,不用了自动会回收,但是C不会 以下del代码为手动强拆,就是从内存中删除变量名

  3. [python学习篇][系统学习][1]python标准库中文、英文网址(一些内建函数,标准库都可以在这里查找)

    http://docspy3zh.readthedocs.io/en/latest/library/   半中文网址 http://usyiyi.cn/translate/python_278/lib ...

  4. 【bzoj4004】[JLOI2015]装备购买 贪心+高斯消元求线性基

    题目描述 脸哥最近在玩一款神奇的游戏,这个游戏里有 n 件装备,每件装备有 m 个属性,用向量zi(aj ,.....,am) 表示 (1 <= i <= n; 1 <= j < ...

  5. NOIP2017赛前模拟(4):总结

    题目: 1.打牌 给定n个整数(n<=1000000),按照扑克牌对子(x,x)或者顺子(x,x+1,x+2)打出牌···问最多可以打出多少次对子或者顺子?牌的大小<=1000000 2. ...

  6. greenplum /postgres 登陆以及创建修改用户密码

    1.greenplum 启动 bin目录下的gpstart  ,-m为只启动master 2.greenplum 启动之后,通过postgresql登陆 登陆命令:PGOPTIONS="-c ...

  7. 使用docker Maven插件本地构建docker镜像并发布到远程服务器

    1.登录网站https://start.spring.io/,生成一个基本的SpringBoot应用. 2.将应用导入Eclipse IDE并创建Application类.目录结构如下: Applic ...

  8. Intellij IDE使用 ideavim,不能复制文档到系统粘贴板

    vim的yank命令默认不会复制到系统粘贴板,而是粘贴到寄存器.你可以使用* 或 +寄存器来访问系统粘贴板. 在~/.ideavimrc (如果不存在就创建) 中添加下列选项 set clipboar ...

  9. 【BZOJ3524】Couriers(主席树)

    题意:给一个长度为n的序列a.1≤a[i]≤n.m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2.如果存在,输出这个数,否则输出0. n,m≤5000 ...

  10. jquery插件的基本写法

    (function($){ var a={name:'2222',age:5555} var b={sex:'男',grade:5555} var c=$.extend({},a,b);//合并到新的 ...