为什么不能在子类的初始化列表里初始化父类的成员
2
3
4
5
6
7
8
9
10
|
class A {
protected:
int n_;
};
class B : public A {
public:
B() : n_(0)
{}
};
|
这是简化的,作为分析问题的。
不解,瞪了几秒钟后以为是access level的问题,于是把protected
改成了public
,但是问题依旧。
又瞪了一段时间才反应过来刚才脑残了,并不是由access level导致的问题。
这个问题的本质是:子类的初始化列表不能初始化父类或者祖先类的成员。
这是标准规定的,至于为什么会有这样一个规定,以及上述的奇怪现象,一个可以参考的解释如下
1)首先是初始化列表的作用
初始化列表其实是一种后天强加的初始化语义。
编译器处理后,会把初始化列表的内容先转化,然后插入到构造函数的开头,之后的内容才是你在构造函数里写的语句,如果你有写的话。
但是,这两部分是截然不同的语义:前者是编译器插入的初始化语句,且开始执行用户自己的语句时,编译期要保证所有需要初始化的成员都已经初始化了,这也是各大书籍推荐使用初始化列表显式初始化成员的原因。
2)继承情况下的初始化顺序
对应一个基类在上的继承树,一个子类对象的初始化顺序是自顶向下。
子类对象的构造函数会首先利用父类的构造函数创建一个父类对象,然后再父类对象的基础之上再把自己创建出来。(想象一个递归调用栈或者后序遍历)
所以,在子类利用构造函数初始化的时候,其父类对象已经是确定构造完毕的
3)标准要求,每个对象在其生命周期内只能被初始化一次. 这是一个非常显然的要求
所以,如果我们在子类的初始化列表中对父类成员进行初始化,那么在子类构造函数开始时,这个对象已经可能被父类构造函数初始化了(内建类型需要显式初始化,带有Non-trivial默认构造的函数就算不指定也会被初始化),因此此时如果子类在初始化,就违反了上述要求3)。
那么这里有个问题:编译器能否检查父类的对象是否已经被初始化,如果是则提示,不是则编译通过?
我个人觉得是完全可以的,intellisense甚至都可以做到。但是如果允许这种行为的话,可能会出现,当你从一个类继承时,你需要沿着继承链向上,判断你需要初始化的父类成员是否已经被他的某个子孙类给初始化了。这显然不是一种好的做法。
而且无论从哪个设计角度,子类初始化父类成员这种越俎代庖的行为都不合理。
至于解决方案,可以对父类的构造函数传参数对其进行初始化。或者结合1)和2)可以推出,在构造函数体里内直接赋值也是可以的
为什么不能在子类的初始化列表里初始化父类的成员相关推荐
- 子类初始化列表不能初始化父类元素 -- class 'Derived' does not have any field named 'x'
缘由 偶尔编写如下代码,编译出错, class Base{public:int x; };class Derived : public Base {public:Derived() : x(10) { ...
- C++经典问题:如果对象A中有对象成员B,对象B没有默认构造函数,那么对象A必须在初始化列表中初始化对象B?
对象成员特点总结: (1)实例化对象A时,如果对象A有对象成员B,那么先执行对象B的构造函数,再执行A的构造函数. (2)如果对象A中有对象成员B,那么销毁对象A时,先执行对象A的析构函数,再执行B的 ...
- C++必须使用【初始化列表】初始化数据成员的三种情况
类对象的构造顺序是这样的: 1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员: 2.进入构造函数后在构造函数中执行一般赋值与计算. 使用初始化列表有两个原因: 原因1.必须这样做: < ...
- 初始化列表||类对象作为类成员|| 静态成员
初始化列表 作用: C++提供了初始化列表语法,用来初始化属性 语法:构造函数():属性1(值1),属性2(值2)... {} #include <iostream> using name ...
- 28.构造函数中,成员变量一定要通过初始化列表来初始化的?
首先要明确:如果对象成员是const或者引用的话,必须将其初始化! 构造函数中,成员变量一定要通过初始化列表来初始化的的几种情况! 1)对象成员是const或者引用 #include <iost ...
- C++类构造函数初始化列表及初始化成员变量的误区
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式.例如: [cpp] view plaincopy class CExample { pub ...
- [面试] C++ 语法(一) —— 初始化列表的初始化顺序
首先来看一道经典的 C++ 面试题: (1)初始化列表的初始化顺序:不是按照列表的顺序进行的 (2)初始化列表的初始化顺序:是按照内存模型中的成员变量的顺序(也即类声明的定义顺序)进行的: (3)也即 ...
- 构造函数中,成员变量一定要通过初始化列表来初始化的几种情况(转载)
1.参考博客 博客链接1 博客链接2 2.实例如下 class A { ... private:int a; }; class B : public A { ... private:A &aa ...
- C++成员变量初始化列表中初始化顺序
1.C++使用初始化列表初始化时,成员变量的初始化顺序:只与定义变量的顺序有关. #include <iostream> using namespace std; class A{ pri ...
最新文章
- 使用Formik轻松开发更高质量的React表单(二)使用指南
- MaxCompute作业日常监控与运维实践
- 生产环境究竟是使用mysqldump还是xtrabackup来备份与恢复数据库?
- 怎么实现两周联动加减速_LOL:野辅联动成版本主旋律,三大辅助对线游走兼备...
- Fmask算法——影像云检测算法
- 美国Compuware败退中国市场!又一家外企逃离
- CMMI3认证和CMMI5认证有哪些不同
- win10新建文件夹必须刷新才能显示
- 京东助手+淘宝试用助手+苏宁试用助手三合一v22102032021
- 数据权限设计思路_权限设计数据权限
- warning: #61-D: integer operation result is out of range
- 360无线wifi电脑怎样连接到服务器,360随身Wifi能连接上但是电脑无法上网怎么办...
- windows 下配置 Nginx 常见问题
- 1092: 地头蛇PIPI
- c语言md5函数 linux,【转】MD5校验C语言实现源代码
- 96Boards MIPI CSI Camera Mezzanine V2.1
- VPP线程之间报文调度
- pycharm的主菜单消失如何解决(“File-Edit-Navigate-View”等菜单丢失)
- 蓝桥杯 ADV-166算法提高 聪明的美食家(java)
- 数字电路与逻辑设计 学习笔记【进制转换】