如何禁止一个类被继承?

当我们想将一个类设置为禁止继承时该用什么方式?有两种解决方案。提示:虚继承与友元!!


Way1:强行将该类的构造函数与析构函数均设为 private,并设定该类的一个友元函数来构建该类对象,并返回指针。此时继承自该类的类将无法调用该类的构造函数,因此将在编译时报错
    • 缺点:将类的使用变得与普通类不兼容,不能在友元函数外定义类对象,用户定义该类必须知道友元函数
    • 优点:简单易理解

Eg:

class A
    {
        friend A* get_Aptr(int);
        A(int i = 0):val(i){}
        int val;
    };

    A * get_Aptr(int i)
    {
        A * ptr = new A(i);            //在用完该对象时还需要手动释放内存空间
        return ptr;
    }

分析:在友元函数外将不能获得实例对象本身,只能获得其指针,但实际上,因为 NRVO(Named return value optimical) 的作用,在某些情况下,将可以返回类对象。如:

Eg:

    class A
    {
        friend A get_A(int);
        //与之前一样
    };

    A get_A(int i)
    {
        A a(i);
        return a;
    }

    int main()
    {
        A a = get_A(3);
    }

分析:

• 若 A 中未定义复制构造函数,则这种使用 get_A(int)的方式正确,此时编译器进行了 NRV 优化,A a = get_A(3)的这句话中并没有调用复制构造函数,因此,该语句正确(g++ 与 VS2013均正确)

• 若A中定义了复制构造函数,且复制构造函数位于private段,则此时用 get_A(int)的方式在编译时报错,但并不代表并未使用 NRV 优化,只是跟编译器的处理方式有关。个人认为:编译器发现复制构造函数在 private 段就会将复制构造操作认为是错误的操作

• 若A中定义了复制构造函数,且赋值构造函数位于 public 段,则此时使用 get_A(int) 的方式正确,但是否进行了NRV 与编译器有关。对 g++ 此时进行了 NRV 优化,对 VS2013 则未进行 NRV 优化

• 在《深入探索C++对象模型》中,李普曼老师说若未定义复制构造函数将不会开启 NRV 优化;但在现在的编译器中,NRV 优化的开启一般都与复制构造函数没有关系,主要由编译器option来决定。


way2 : 定义一个类A,将其构造函数与析构函数均放在 private 段,并将类 B 设为类A 的友元,让 B 虚继承自 A,B将变为不可继承的类。使用类C 继承类B 来检查是否不可继承

分析:在该过程中有两个重要操作,<1>将 类B 设为类A 的友元,<2>将类B 虚继承自类A。以下逐个分析。

• 将B设为A的友元后,B可以访问A的私有构造函数与析构函数,则B的使用正常,从理论上说,新定义一个类C 将不能继承类B,因为类C 不能访问 A类子对象的构造函数

§ 问题:事实上,若只是如此,将能够通过编译,因为 A类子对象的构造函数将有 B类子对象调用,而 B类子对象是 A类子对象的友元,因此能通过编译

§ 解决方法:强行让最底层的派生类访问基类的构造函数,即让 C类对象直接访问 A类子对象的构造函数,而不能让 B类子对象访问 A类子对象的构造函数

• 要使类C 的对象直接访问 A子对象的构造函数,办法是使 A 类成为派生链中的虚基类

§ 虚基类的子对象由继承链中最低层的类对象维护,因此类A 的子对象将由链中最底层的 类C 的对象调用,而类C 没有类A 子对象的构造函数的访问权,因此,类C 的继承操作将报错

说明:

• 缺点:理解起来比较复杂
• 优点:使用不可继承的类与使用一般类相同

<think>好的,用户问的是如何在C++中禁止被其他继承。我需要先回忆一下相关的知识。记得在C++中,如果想阻止一个继承,可以使用final关键字。不过得确认这个关键字的用法,是不是加在声明后面。比如class Base final {}; 这样Base就不能被继承了。 那用户可能想知道具体的语法和示例。我应该举一个例子,比如定义一个被final修饰的,然后尝试继承它,编译器会报错。这样用户能直观地看到效果。 另外,可能还需要说明在C++11之前,没有final关键字,那时候有没有其他法?比如使用私有构造函数和友元或者静态成员函数来控制构造,但这种法比较复杂,而且可能不够直观。不过用户可能只需要现代的法,即使用final,所以重点应该放在这上面。 需要确保回答的结构清晰,分步骤说明。首先介绍final关键字的用法,然后给出代码示例,说明继承时会报错。可能还需要提到final也可以用于虚函数,防止进一步重写,但用户的问题是关于继承的,所以这部分可能作为补充信息。 还要检查是否有其他法,比如使用私有派生控制,但C++中如果没有final,可能很难完全禁止继承。所以final是最直接的法。 最后,确认语法正确,用中文回答,结构符合用户的要求,分点说明,并给出示例代码。可能需要提醒用户注意C++的版本,因为final是C++11引入的,所以需要编译器支持C++11或更高版本。</think>在 C++ 中禁止继承,可以通过以下步骤实现: ### 法:使用 `final` 关键字 C++11 引入的 `final` 关键字可以直接禁止继承,这是最简洁高效的解决案。 #### 实现步骤 1. **声明时添加 `final`** 在名后添加 `final` 关键字: ```cpp class Base final { // 添加 final 关键字 public: void func() {} }; ``` 2. **尝试继承会触发编译错误** 若尝试派生子: ```cpp class Derived : public Base {}; // 编译器报错 ``` 编译器会提示错误: ``` error: cannot derive from 'final' base 'Base' in derived type 'Derived' ``` #### 原理说明 - `final` 关键字通过编译器强制检查实现继承限制 - 语义清晰直观,优于传统的复杂技巧 - 属于编译期检查,无运行时开销 ### 传统替代案(C++11 前) 若需兼容旧标准,可通过限制构造函数实现: ```cpp class NoInherit { private: NoInherit() {} // 私有构造函数 public: static NoInherit create() { return NoInherit(); // 通过静态法创建实例 } }; // 派生无法访问基私有构造函数 class Child : public NoInherit {}; // 编译错误 ``` ### 关键对比 | 法 | 版本要求 | 实现复杂度 | 错误检测阶段 | |-----------|--------|-------|--------| | `final` | C++11+ | 简单 | 编译期 | | 私有构造函数 | 任意版本 | 复杂 | 编译期 | ### 使用建议 1. 优先使用 `final` 关键字(需编译器支持 C++11+) 2. 明确标记不需要扩展的,增强代码安全性 3. 适用于工具、不可变对象等不需要多态的场景 示例建议编译命令: ```bash g++ -std=c++11 your_file.cpp # 需开启 C++11 支持 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值