在C++中如何阻止类被继承详解

这个话题是源自于一个面试题,我在网上查了一下有不少这方面的解说!我自己整理了一下,选择了一个自认为是最优方案!

我们从最简单的开始:

首先,大家都知道要阻止类被实例化,可以通过使用private or protected 关键字来声明默认构造函数。那么在阻止类被继承的时候,我们需要用到这个技巧。其次,阻止类被继承还需要使用private来控制继承的基类。

namespace SamplePrivate
{
#ifdef NDEBUG
    class Sealed
    {
        protected:
            Sealed() {};
            friend class SampleSealedClass; // 设置友类,以便访问Sealed的构造函数
    };
    class SampleSealedClass : private virtual Sealed
    {
    };
#else
    class SampleSealedClass {}
#endif
}

这样我们就可以实例化SampleSealedClass,并且还不用担心被继承了。不过还是要解释一下为什么阻止了继承?

当我们写出下面的代码时,编译器在编译过程中做了什么呢?

class subclass : public SampleSealedClass
{
};

首先,当你在实例化subclass的时候,会先调用SampleSealedClass的构造函数,而在这之前会调用Sealed类的默认构造函数,但是我们发现Sealed是不能被实例化的,并且通过private virtual的继承只能被SampleSealedClass调用,因此这很好的阻止了类被继承。但是这里我们只能完成一个类被不被继承,那么是否有更好的方法来实现阻止任意类被继承呢?

那就需要用到模板了:

#ifdef NDEBUG
namespace SealedClasses
{
    class Sealed
    {
        protected:
            Sealed() {}
    };
    template<class T> class TypeWapper
    {
        public:
            typedef T type;
    };
}
template<typename T> class BaseSealed : private virtual SealedClasses::Sealed
{
    friend class SealedClasses::TypeWapper<T>::type;
};
#else
template<typename T> class BaseSealed
{
};
#endif

这里的TypeWapper主要是将外部类型传递到SealedClasses的,从而能得到访问Sealed构造函数的能力。不过这段代码在GCC4.0中通过编译,而在vs2008中不能通过。可以向下面这样来引用:

class subclass : BaseSealed<subclass>
{
    public:
        subclass() { cout << "subclass" << endl; }
};
// 下面这个会编译失败
class ssubclass : public subclass
{
    public:
        ssubclass() { cout << "ssubclass" << endl; }
};

将想法付诸于实践,借此来影响他人是一个人存在的真正价值

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C++类继承 继承后函数的值实现详解

    类的继承会首先寻找基类,若基类未实现,则会寻找派生类的函数 1. class继承,函数不继承 #include <stdio.h> class Base { public: Base(){} ~Base(){} int a; void setA() { a = 1; } }; class A:public Base { public: A(){} ~A(){} void setA() { a = 2; } }; class B:public Base { public: B(){} ~B(){

  • C++类继承之子类调用父类的构造函数的实例详解

    C++类继承之子类调用父类的构造函数的实例详解 父类HttpUtil: #pragma once #include <windows.h> #include <string> using namespace std; class HttpUtil { private: LPVOID hInternet; LPVOID hConnect; LPVOID hRequest; protected: wchar_t * mHostName; short mPort; string send

  • C++类中的继承实例详解

    C++类中的继承实例详解 实例效果: 实现代码: #include<iostream> #include<string> using namespace std; class Person { public: Person(const char* name = "abc") :_name(name) { cout << "Person()" << endl; } Person(const Person& pp)

  • 详解C++基础——类继承

    一.前言 好吧,本系列博客已经变成了<C++ Primer Plus>的读书笔记,尴尬.在使用C语言时,多通过添加库函数的方式实现代码重用,但有一个弊端就是原来写好的代码并不完全适用于现在的情况.OOP设计思想中类的继承相比来说更为灵活,可以添加新的数据成员和方法,也能修改继承下来方法的实现细节,同时还保留了原有的代码.开始进入正题. 二.类继承示例 场景如下:现需要记录乒乓球运动成员的信息,包括姓名和有无空余桌台.其中有一部分成员参加过比赛,需要将这一部分单独提出并记录他们在比赛中的比分.因

  • 详解C++基础——类继承中方法重载

    一.前言 在上一篇C++基础博文中讨论了C++最基本的代码重用特性--类继承,派生类可以在继承基类元素的同时,添加新的成员和方法.但是没有考虑一种情况:派生类继承下来的方法的实现细节并不一定适合派生类的需求,此时派生类需要重载集成方法. 二.重载方法及虚函数 我们讨论<C++ Primer Plus>中的如下场景:银行记录客户信息,包括客户姓名.当前余额.客户这一类别当然能够创建客户对象.存款.取款以及显示信息.银行需要特殊记录具有透支权限的客户,因此这一类别的客户要额外记录透支上限.透支贷款

  • C++中继承与多态的基础虚函数类详解

    前言 本文主要给大家介绍了关于C++中继承与多态的基础虚函数类的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 虚函数类 继承中我们经常提到虚拟继承,现在我们来探究这种的虚函数,虚函数类的成员函数前面加virtual关键字,则这个成员函数称为虚函数,不要小看这个虚函数,他可以解决继承中许多棘手的问题,而对于多态那他更重要了,没有它就没有多态,所以这个知识点非常重要,以及后面介绍的虚函数表都极其重要,一定要认真的理解~ 现在开始概念虚函数就又引出一个概念,那就是重写(覆

  • 在C++中如何阻止类被继承详解

    这个话题是源自于一个面试题,我在网上查了一下有不少这方面的解说!我自己整理了一下,选择了一个自认为是最优方案! 我们从最简单的开始: 首先,大家都知道要阻止类被实例化,可以通过使用private or protected 关键字来声明默认构造函数.那么在阻止类被继承的时候,我们需要用到这个技巧.其次,阻止类被继承还需要使用private来控制继承的基类. namespace SamplePrivate { #ifdef NDEBUG class Sealed { protected: Seale

  • C++中对象与类的详解及其作用介绍

    目录 什么是对象 面向过程 vs 面向对象 面向过程 面向对象 什么是类 类的格式 类的成员函数 函数访问权限 方法一 方法二 方法三 inline 成员函数 什么是对象 任何事物都是一个对象, 也就是传说中的万物皆为对象. 对象的组成: 数据: 描述对象的属性 函数: 描述对象的行为, 根据外界的信息进行相应操作的代码 具有相同的属性和行为的对象抽象为类 (class) 类是对象的抽象 对象则是类的特例 面向过程 vs 面向对象 面向过程 面向过程的设计: 围绕功能, 用一个函数实现一个功能

  • C#中的Hashtable 类使用详解

    目录 一:Hashtable 类简单说明 二:Hashtable 类的构造函数 三:Hashtable 类的属性 四:Hashtable 类的常用方法 1: Hashtable.Add(Object, Object) 的方法介绍 2: Hashtable.Clone ()的方法介绍 3: Hashtable.ContainsKey(Object)和ContainsValue(Object)的方法介绍 4:Hashtable.Remove(Object)的方法介绍 一:Hashtable 类简单说

  • Python中如何导入类示例详解

    前言 随着我们不断地在一个文件中添加新的功能, 就会使得文件变得很长. 即便使用了继承,也抑制不住类的成长.为了解决这一问题,我们可以将类存储在模块中, 然后在主程序中导入所需的模块,这样可以让文件尽可能保持整洁,从而实现更好的管理. 导入类是一种很有效的编程方式. 这样我们就可以把大部分逻辑存储在独立的文件中,然后在主程序编写高级逻辑咯O(∩_∩)O哈哈~ 1 导入一个类 假设有一个 User 类,文件名为 User.py,这个待导入的文件,一般称为模块: class User(): '''账

  • java中的PriorityQueue类过程详解

    目录 一.什么是优先级队列 1.概念 2.案例演示特性 3.数据结构 一.什么是优先级队列 1.概念 我们都知道队列,队列的核心思想就是先进先出,这个优先级队列有点不太一样.优先级队列中,数据按关键词有序排列,插入新数据的时候,会自动插入到合适的位置保证队列有序.(顺序有两种形式:升序或者是降序) 来一个标准点的定义: PriorityQueue类在Java1.5中引入.PriorityQueue是基于优先堆的一个无界队列,这个优先队列中的元素可以默认自然排序或者通过提供的Comparator(

  • C#中的HttpWebRequest类用法详解

    HttpWebRequest 是一个Http 请求类,继承于 WebRequest. WebRequest 是一个抽象类,能够对统一资源标识符 (URI) 发出请求. WebRequest 有以下派生类: System.IO.Packaging.PackWebRequest System.Net.FileWebRequest System.Net.FtpWebRequest System.Net.HttpWebRequest 使用时 using System.Net; 1,HttpWebRequ

  • .NET Core中的HttpClientFactory类用法详解

    一.HttpClient使用 在C#中,如果我们需要向某特定的URL地址发送Http请求的时候,通常会用到HttpClient类.会将HttpClient包裹在using内部进行声明和初始化,如下面的代码: using (var httpClient = new HttpClient()) { // 逻辑处理代码 } HttpClient类包含了许多有用的方法,使用上面的代码,可以满足绝大多数的需求,但是如果对其使用不当时,可能会出现意想不到的事情. 上面代码的技术范点:当你使用继承了IDisp

  • Asp.Net中Cache操作类实例详解

    本文以一个Asp.Net的Cache操作类实例代码来详细描述了cache缓存的结构及实现方法,完整代码如下所示: /// <head> /// <function> /// 存储类(存储UserInfo信息) /// </function> /// <description> /// 用Cache存储用户信息 /// 在指定间隔(TimeOut)内取,则可以从Cache中取, /// 如果超出存储时间,则从数据库取用户信息数据 /// 作為所有用户信息的存儲

  • Python类中的装饰器在当前类中的声明与调用详解

    我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器. 代码如下: class Test(): xx = False def __init__(self): pass def test(func): def wrapper(self, *args, **kwargs): print(self.xx) return func(self, *args, **kwargs) return wrapper @test def test_a(self,a,b): pr

  • java开发中嵌套类的详解及实例

     java开发中嵌套类的详解 在java语言规范里面,嵌套类(Nested Classes)定义是: A nested class is any class whose declaration occurs within the body of another class or interface. A top level class is a class that is not a nested class. 说的简单一点,就是定义在类里面的类.一般把定义内部类的外围类成为包装类(enclos

随机推荐