C++终结类

C++如何实现不能被继承的类,即终结类。Java中有final关键字修饰,C#中有sealed关键字修饰,C++11之前还没有类似的关键字来修饰类实现终结类,需编程人员手动实现。但从C++11开始,提出了final关键字来申明终结类。

现在不通过C++11关键词final,来实现一个被能被继承的类。由于任何派生类的对象在创建的时候,都必需在派生类的构造函数中调用父类的构造函数。所以,只要类的构造函数在子类中无法被访问,那么就阻止了该类被继承,实现终结类。

如果将一个类的构造函数声明为私有(private),可以阻止该类进一步派生,但是该类也无法直接实例化了,此方法行不通。注意,构造函数为private的类,无法直接实例化,但是可以被间接实例化。间接实例化方法是:类中定义一个公有的静态成员函数,由这个函数来完成对象的初始化工作。联想到C++的单例模式Singleton,也是用到了这个方法,C++的单例模式的实现见如下代码:

class CSingleton  
{  
private:  
    CSingleton(){};   //构造函数是私有的  
    static CSingleton *m_pInstance;  
public:  
    static CSingleton * GetInstance()  
    {  
        if(m_pInstance == NULL)  //判断是否第一次调用  
            m_pInstance = new CSingleton();  
        return m_pInstance;  
    }  
};  

C++中实现不能被继承的类的最为有效安全方便的方法是使用“虚拟继承”。一个基类如果被虚拟继承,那么在创建它的孙子类的对象时,该基类的构造函数需要单独被调用。此时,如果该基类的构造函数在孙子类的构造函数中无法访问,那么就实现了基类的子类不能被继承。

利用虚拟继承的这种特性,我们可以设计出这样一个基类FinalParent,它不定义任何数据成员,这样任何类从它派生并不会增加任何空间上的开销。将它的默认构造函数的访问权限设定为protected,这样它自身不能产生任何实例,只能用作基类。一个使用基类FinalParent的实现终结类的例子如下:

#include <iostream>
using namespace std;
class FinalParent
{
protected:
FinalParent();
};

class FinalClass:private virtual FinalParent
{
public:
  FinalClass():num(1){};
  void show()
  {
     cout<<"num:"<<num<<endl;
  }
private:
  int num;

};

class FinalClassChild:public FinalClass
{
  int a;
public:
  FinalClassChild():a(0){};
};

int main(int argc,char* argv[])
{
  FinalClassChild f;    //报错,无法访问FinalParent::FinalParent()
  return 0;
}

从程序中可以看出,当FinalClassChild试图继承FinalClass的时候,FinalClassChild的构造函数中需要调用FinalParent的构造函数,而FinalParent的构造函数在FinalClass中已经变成了私有private,不能被FinalClassChild的任何成员函数所访问,导致编译错误。所以,任何一个类,只要虚拟继承类FinalParent,就不能被继续,从而简单、高效安全的实现了“终结类”。


参考文献

[1]陈刚.C++高级进阶教程[M].武汉:武汉大学出版社,2008:280-282

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Micro_awake web

es6(一):es6介绍以及let,const

es是js的规范,而js是具体实现 将es6转化为es5代码工具:运用的多的是babel 在线转换地址:babel,traceur(属于谷歌) 1.let申明变...

2119
来自专栏听雨堂

Python基础语法学习整理

1、基础 r’  ‘:原始字符串 pow、round是内建函数 2、序列通用操作: 索引:d[] 分片:[:] 相加:d+[] 乘法:[1,2]*3...

2206
来自专栏Golang语言社区

Go语言基本的语法和内置数据类型初探

Go令牌 Go程序包括各种令牌和令牌可以是一个关键字,一个标识符,常量,字符串文字或符号。例如,下面的Go语句由六个令牌: fmt.Println("Hell...

2815
来自专栏阿凯的Excel

Python读书笔记12(IF语句应用)

今天和大家分享的是所有函数、所有编程的基础,判断! IF语句! IF语句肯定是进行判断,为真怎样,为假如何。 那这个真假就是某个条件是否满足,和Python相...

3729
来自专栏移动端开发

Swift 面向对象解析(二)

 接着上面一篇说的内容: 一 继承:      苹果继承与水果,苹果是水果的子类,则苹果是一种特殊的水果;这就是继承的关系,这个我们学OC的时候相信也都理解了...

2307
来自专栏吴伟祥

MySQL中字节、编码、长度、值的关系 原

0.一个汉字占多少字节与编码有关:          UTF-8:一个汉字=3个字节             GBK:一个汉字=2个字节  1.var...

903
来自专栏菜鸟计划

javascript 基本概念

一、在HTML中使用javascript 1.直接是用<script></script>标签。 2.外部引入 <script type="javascript"...

2633
来自专栏pangguoming

JavaScript的IIFE(即时执行方法)

前面的话   严格来讲,IIFE并不是闭包,因为它并不满足函数成为闭包的三个条件。但一般地,人们认为IIFE就是闭包,毕竟闭包有多个定义。本文将详细介绍IIFE...

3175
来自专栏java学习

java每日一练(2017/9/16)

本期题目 (单选题) 1、代码String str=”123456a”;int i=Integer.parseInt(str);会报异常的是() A java...

3778
来自专栏我和我大前端的故事

初探 TypeScript函数基本类型泛型接口类内置对象

前段时间有朋友和我推荐 TypeScript ,他说写起来特别爽,让我去试一试,那时候我还在那是啥高深莫测的东西。刚好那段时间忙,一直没有时间看。最近也很忙,还...

5812

扫码关注云+社区

领取腾讯云代金券