文档章节

c++设计一个不能被继承的类,为什么必须是虚继承?原因分析

___Null
 ___Null
发布于 2014/09/30 22:47
字数 655
阅读 5774
收藏 99

用C++实现一个不能被继承的类(例1)

#include <iostream>
using namespace std;

template <typename T>
class Base{
    friend T;
private:
    Base(){
        cout << "base" << endl;
    }
    ~Base(){}
};

class B:virtual public Base<B>{   //一定注意 必须是虚继承
public:
    B(){
        cout << "B" << endl;
    }
};

class C:public B{
public:
    C(){}     //继承时报错,无法通过编译
};


int main(){
    B b;      //B类无法被继承
    //C c;
    return 0;
}

类Base的构造函数和析构函数因为是私有的,只有Base类的友元可以访问,B类在继承时将模板的参数设置为了B类,所以构造B类对象时们可以直接访问父类(Base)的构造函数。

为什么必须是虚继承(virtual)呢?

参见 c++Primer 4th 第17.3.7节 特殊的初始化语义

     通常每个类只初始化自己的直接基类,但是在虚继承的时候这个情况发生了变化,可能导致虚基类被多次初始化,这显然不是我们想要的。(例2: AA,AB都是类A的派生类,然后类C又继承自AA和AB,如果按之前的方法会导致C里面A被初始化两次,也会存在两份数据)

    为了解决重复初始化的问题,从具有虚基类的类继承的类在初始化时进行了特殊处理,在虚派生中,由最低层次的派生类的构造函数初始化虚基类。在我们上面的例1中就是由C的构造函数控制如何进行虚基类的初始化。

为什么B类不能被继承?

   回到例1,因为B是Base的友元,所以B对象可以正常创建,但由于B使用了虚继承,所以如果要创建C对象,那么C类的构造函数就要负责虚基类(Base)的构造,但是Base的构造函数是私有的,C没有访问的权限(ps:友元关系不能被继承的),所以例1中的C类在编译时就会报错。这样B类就不能被继承了。

----------------------------------------------------

吐槽一下:面试中被问到这个问题,虽然答出了实现方法,但是原理没回答上,于是回来之后查了一下

大家都说这属于“奇技淫巧”,哎,面试官就爱问这些 我也很无语啊


© 著作权归作者所有

___Null
粉丝 16
博文 13
码字总数 6385
作品 0
珠海
程序员
私信 提问
加载中

评论(12)

梁欢
梁欢

引用来自“xlplbo”的评论

总结一下:
1,虚继承的一个特征就是虚基类A的构造函数由最终子类B负责构造(解释了为什么要虚继承)
2,虚基类A构造函数定义为private,子类B通过作为基类A的friend类来访问基类A的构造函数
3,子类C继承至父类B,但不继承友元属性,子类C无法调用基类A的构造函数(参看第一点),所以B是final class
4,第4行friend T;在g++4.8编译器下无法通过编译。friend class T;也不行,求解决。。。

如果不想用模板只需要将构造函数定义成私有的就行了。
borey
borey
总结一下:
1,虚继承的一个特征就是虚基类A的构造函数由最终子类B负责构造(解释了为什么要虚继承)
2,虚基类A构造函数定义为private,子类B通过作为基类A的friend类来访问基类A的构造函数
3,子类C继承至父类B,但不继承友元属性,子类C无法调用基类A的构造函数(参看第一点),所以B是final class
4,第4行friend T;在g++4.8编译器下无法通过编译。friend class T;也不行,求解决。。。
___Null
___Null 博主

引用来自“哆啦比猫”的评论

引用来自“___Null”的评论

引用来自“噢哟哪”的评论

意义何在
java里面final的意义何在 c++11里面的final意义何在

有了 final 还这样写意义何在
c++11普及之后这样写确实就没什么意义了
一如当初
一如当初
面试就这样,甚至问的东西跟公司业务都不想干。这些所谓面试官就是为了提升逼格,看多了。
哆啦比猫
哆啦比猫

引用来自“___Null”的评论

引用来自“噢哟哪”的评论

意义何在
java里面final的意义何在 c++11里面的final意义何在

有了 final 还这样写意义何在
Chriesh
Chriesh
还行
___Null
___Null 博主

引用来自“噢哟哪”的评论

意义何在
java里面final的意义何在 c++11里面的final意义何在
一只囧蟹
一只囧蟹
意义何在
___Null
___Null 博主

引用来自“老帖子”的评论

请无视这些奇葩的奇技淫巧,换用final
http://en.cppreference.com/w/cpp/language/final
面试中被问到了,所以我就总结了一下,
老帖子
请无视这些奇葩的奇技淫巧,换用final
http://en.cppreference.com/w/cpp/language/final
C++继承的话题

析构函数 如果一个类想被别人继承,通常析构函数要声明为虚函数,否则,如下代码就会出现未定义情况。 Base* p=new Derived(); delete p; 这句话反过来说,就是如果你不打算让别人派生你的类...

长平狐
2012/08/28
109
0
带Body的纯虚函数与不带Body的虚函数?(C++学习)

虚函数 纯虚函数 基类本身可生成对象 基类本身不能生成对象 基类中必须提供实现 必须在派生类中提供实现 "实体继承" "接口继承" 纯虚函数 带纯虚函数的类叫虚基类(也叫抽象类),这种基类不能...

晨曦之光
2012/05/08
409
0
使用C++11继承控制关键词来防止在类层次结构上的不一致

30多年来,C++一直没有继承控制关键字。最起码这是不容易的。禁用一个类的进一步衍生是可能的但也很棘手。为避免用户在派生类中重载一个虚函数,你不得不向后考虑。但没有更多了:两个新的上...

oschina
2013/04/12
4.4K
4
C++灵魂所在之---多态的前世与今生

开头先送大家一句话吧: 众所周知,在20世纪80年代早期,C++在贝尔实验室诞生了,这是一门面向对象的语言,但它又不是全新的面向对象的语言,它是在传统的语言(C语言)进行面向对象扩展而来...

loving_forever_
2016/06/13
0
0
绕开“陷阱“,阿里专家带你深入理解C++对象模型的特殊之处

摘要:本文介绍了C++对象模型的特殊之处,包括与C兼容的朴素模型,以及能支持多态的虚表模型,同时还带大家了解了构造函数与析构函数相关的一些特性与陷阱。这些内容能够帮助大家更好地学习和...

nirvanalucky
2018/04/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

springboot2.0 maven打包分离lib,resources

springboot将工程打包成jar包后,会出现获取classpath下的文件出现测试环境正常而生产环境文件找不到的问题,这是因为 1、在调试过程中,文件是真实存在于磁盘的某个目录。此时通过获取文件路...

陈俊凯
今天
4
0
BootStrap

一、BootStrap 简洁、直观、强悍的前端开发框架,让web开发更加迅速、简单 中文镜像网站:http://www.bootcss.com 用于开发响应式布局、移动设备优先的WEB项目 1、使用boot 创建文件夹,在文...

wytao1995
今天
9
0
小知识:讲述Linux命令别名与资源文件的区别

别名 别名是命令的快捷方式。为那些需要经常执行,但需要很长时间输入的长命令创建快捷方式很有用。语法是: alias ppp='ping www.baidu.com' 它们并不总是用来缩短长命令。重要的是,你将它...

老孟的Linux私房菜
今天
8
0
《JAVA核心知识》学习笔记(6. Spring 原理)-5

它是一个全面的、企业应用开发一站式的解决方案,贯穿表现层、业务层、持久层。但是 Spring 仍然可以和其他的框架无缝整合。 6.1.1. Spring 特点 6.1.1.1. 轻量级 6.1.1.2. 控制反转 6.1.1....

Shingfi
今天
7
0
Excel导入数据库数据+Excel导入网页数据【实时追踪】

1.Excel导入数据库数据:数据选项卡------>导入数据 2.Excel导入网页数据【实时追踪】:

东方墨天
今天
8
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部