From:http://blog.csdn.net/lazy_tiger/article/details/2224899

一个类不能被继承,也就是说它的子类不能构造父类,这样子类就没有办法实例化整个子类从而实现子类无法继承父类。我们可以将一个类的构造函数声明为私有,使得这个类的构造函数对子类不可见,那么这个类也就不能继承了。但是,这引出一个问题,客户程序岂不是也无法实例化这个类了?OK,让我们参考一下Singleton模式,用一个static函数来帮助创建这个类的实例,问题就解决了!

class CParent
{
private:
    CParent(int v){m_v = v;}
    ~CParent(){}

    int m_v;
    static CParent * m_instance;
public:
void fun(){cout << "The value is: " << m_v << endl;}
    static CParent * getInstance(int v);
};
CParent * CParent::m_instance = NULL;

CParent * CParent::getInstance(int v)
{
    m_instance = new CParent(v);
    return m_instance;
}

这是一个有效的方法,但是static函数创建出来的实例必然是static的。而且,这个类不能像普通的类那样构建对象,比如:

CParent c;  // impossible

换个思路考虑一下,友元不也是不能被继承的么?我们可以把类的构造函数定义为private的同时,定义友元函数来帮助构造类的实例。

class CParent
{
private:
    CParent(int v){m_v = v;}
    ~CParent();

    int m_v;
public:
    void fun(){cout << "The value is: " << m_v << endl;}
    friend CParent * getInstance(int v);
};

CParent * getInstance(int v)
{
    CParent * pinstance = new CParent(v);
    return pinstance;
}

这个类也是不能被继承的,但是出现的问题和前面一样:我们还是不能像对普通类那样对待这个类。

现在设想一下,有一个CParent类,我们不希望他能够被继承。在友元不能被继承的思路指引下,我们要考虑让CParent的友元属性不能被继承。假设有一个辅助类CNoHeritance,CParent是CNoHeritance类的友元。还要假设一个CChild类,它试图去继承CParent类(如果它有这个能耐的话)。

先把CNoHeritance类的构造函数定义成private,然后将CParent声明为CNoHeritance的友元类。同时CParent继承了CNoHeritance类。到目前为止,CNoHeritance除了CParent类以外,谁也无法对它进行访问和实例化。CChild因为无法继承CParent的友元特性,所以CChild无法对CNoHeritance直接进行实例化(但是可以通过CParent)。

到目前为止,CParent还是可以被继承的。这是一个trick.让我们整理一下思路,下面的图说明了CNoHeritance, CParent和CChild三个类之间的关系。

如果我们让CParent类虚继承CNoHeritance类,根据虚继承的特性,虚基类的构造函数由最终的子类负责构造。因此CChild如果要想继承CParent,它必须能够构造CNoHeritance,这是不可能的!因此,我们的CParent也就终于成为了一个无法继承的类。

class CNoHeritance
{
private:
    CNoHeritance(){}
    ~CNoHeritance(){}
    friend class CParent;
};

class CParent : virtual public CNoHeritance
{
public:
    CParent(int v){m_v = v;}
    ~CParent(){};
private:
    int m_v;

public:
    void fun(){cout << "The value is: " << m_v << endl;}
};

class CChild : public CParent
{
public:
    CChild():CParent(10){}
    ~CChild(){}
};

需要注意的是,我们这里引入的CNoHeritance类对整个程序而言,只引入了Private的构造函数和析构函数,所以不会因为可能的菱形继承带来二义性.

[转]实现一个无法被继承的C++类的更多相关文章

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

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

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

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

  3. 用C++设计一个不能被继承的类(转)

    在Java 中定义了关键字final,被final修饰的类不能被继承. 首先想到的是在C++中,子类的构造函数会自动调用父类的构造函数.同样,子类的析构函数也会自动调用父类的析构函数.要想一个类不能被 ...

  4. 3.实现一个名为Person的类和它的子类Employee,Employee有两个子类Faculty 和Staff。

    23.实现一个名为Person的类和它的子类Employee,Employee有两个子类Faculty 和Staff. 具体要求如下: (1)Person类中的属性有:姓名name(String类型) ...

  5. classmethod一个用处是创建可选类构造器

    Definition and Introduction通常来说, descriptor 是一种绑定着特殊行为属性的对象, 在访问它时行为被descriptor协议定义的方法所重载.这些方法是__get ...

  6. 一天一个Java基础——对象和类

    1.在Java中你所做的全部工作就是定义类,产生那些类的对象,以及发送消息给这些对象 2.可以在类中设置两种类型的元素:字段(也被称作数据成员)和方法(也被称作成员函数) 3.字段可以是任何类型的对象 ...

  7. 一个漂亮的php验证码类

    一个漂亮的php验证码类(分享)   作者: 字体:[增加 减小] 类型:转载 下面小编就为大家分享一个漂亮的php验证码类.需要的朋友可以过来参考下   直接上代码: 复制代码 代码如下: //验证 ...

  8. 设计一个 Java 程序,自定义异常类,从命令行(键盘)输入一个字符串,如果该字符串值为“XYZ”。。。

    设计一个 Java 程序,自定义异常类,从命令行(键盘)输入一个字符串,如果该字符串值为“XYZ”,则抛出一个异常信息“This is a XYZ”,如果从命令行输入 ABC,则没有抛出异常.(只有 ...

  9. CSS一个元素同时使用多个类选择器(class selector)

    CSS类选择器参考手册 一个元素同时使用多个类选择器 CSS中类选择器用点号表示.实际项目中一个div元素为了能被多个样式表匹配到(样式复用),通常div的class中由好几段组成,如<div ...

随机推荐

  1. Android属性动画

    这几天看郭神的博客 Android属性动画完全解析(上),初识属性动画的基本用法之后,我自己突然想实现一种动画功能,就是我们在携程网.阿里旅行等等手机APP端买火车票的时候,看到有选择城市,那么就有出 ...

  2. 【干货】”首个“ .NET Core 验证码组件

    前言 众所周知,Dotnet Core目前没有图形API,以前的System.Drawing程序集并没有包含在Dotnet Core 1.0环境中.不过在dotnet core labs项目里可以见到 ...

  3. HTTPS那些事(一)HTTPS原理

    转载来自:http://www.guokr.com/post/114121/ 谣言粉碎机前些日子发布的<用公共WiFi上网会危害银行账户安全吗?>,文中介绍了在使用HTTPS进行网络加密传 ...

  4. 微信支付:H5吊起支付API,不显示“确认支付、输入密码”界面

    使用公众号进行支付,官方开发帮助文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1 其业务流程如下: 按照业务流程进行开发 ...

  5. 基础总结之Activity

    一.万事开头的序 网上看见大牛们的博客写的那样精彩,各种羡慕之情溢于言表.几次冲动均想效仿牛人写些博客来记录下自己的心得体会,但均无感亦或是感觉容易被喷,相信很多菜鸟和我一样都有过这样的担忧.万事开头 ...

  6. Cobar + MySQL 技术验证(li)

    一.简介 Cobar是一个对数据进行拆分后进行分布式存储的产品,可以支持使用后台的 MySQL或者Oracle数据库,通过配置,将数据按照一定规则存储入不同的数据库中.即用分布式数据库代替了集中式数据 ...

  7. WCF入门教程2——创建第一个WCF程序

    本节目标 掌握接口 理解契约式编程 创建宿主程序 创建客户端程序访问服务 什么是接口 认识一下接口 必须知道的接口特性 接口不可以被实例化(常作为类型使用) 实现类必须实现接口的所有方法(抽象类除外) ...

  8. axis2生成客户端代码

    通过aix2生成客户端代码需要准备相应的包,然后执行命令,步骤如下: 一.所需包准备 下载axis2-1.6.2-bin.zip,解压从lib包中取出 jaxrpc.jar wsdl4j-1.6.2. ...

  9. 使用 jQuery Ajax 在页面滚动时从服务器加载数据

    简介 文本将演示怎么在滚动滚动条时从服务器端下载数据.用AJAX技术从服务器端加载数据有助于改善任何web应用的性能表现,因为在打开页面时,只有一屏的数据从服务器端加载了,需要更多的数据时,可以随着用 ...

  10. Windows消息机制

    Windows的消息系统是由3个部分组成的: · 消息队列.Windows能够为所有的应用程序维护一个消息队列.应用程序必须从消息队列中获取消息,然后分派给某个窗口.· 消息循环.通过这个循环机制应用 ...