为什么不能在子类的初始化列表里初始化父类的成员

好几次遇到此类问题了:便不得不找些资料弄明白它;
具体代码是:
2
3
4
5
6
7
8
9
10
class A {
protected:
    int n_;
};
class B : public A {
public:
    B() : n_(0)
    {}
};
这是简化的,作为分析问题的。
然后无情的报错:
|error: class 'B' does not have any field named 'n_'

不解,瞪了几秒钟后以为是access level的问题,于是把protected改成了public,但是问题依旧。

又瞪了一段时间才反应过来刚才脑残了,并不是由access level导致的问题。

这个问题的本质是:子类的初始化列表不能初始化父类或者祖先类的成员

这是标准规定的,至于为什么会有这样一个规定,以及上述的奇怪现象,一个可以参考的解释如下

1)首先是初始化列表的作用

初始化列表其实是一种后天强加的初始化语义。

编译器处理后,会把初始化列表的内容先转化,然后插入到构造函数的开头,之后的内容才是你在构造函数里写的语句,如果你有写的话。

但是,这两部分是截然不同的语义:前者是编译器插入的初始化语句,且开始执行用户自己的语句时,编译期要保证所有需要初始化的成员都已经初始化了,这也是各大书籍推荐使用初始化列表显式初始化成员的原因。

2)继承情况下的初始化顺序

对应一个基类在上的继承树,一个子类对象的初始化顺序是自顶向下

子类对象的构造函数会首先利用父类的构造函数创建一个父类对象,然后再父类对象的基础之上再把自己创建出来。(想象一个递归调用栈或者后序遍历)

所以,在子类利用构造函数初始化的时候,其父类对象已经是确定构造完毕的

3)标准要求,每个对象在其生命周期内只能被初始化一次. 这是一个非常显然的要求

所以,如果我们在子类的初始化列表中对父类成员进行初始化,那么在子类构造函数开始时,这个对象已经可能被父类构造函数初始化了(内建类型需要显式初始化,带有Non-trivial默认构造的函数就算不指定也会被初始化),因此此时如果子类在初始化,就违反了上述要求3)。

那么这里有个问题:编译器能否检查父类的对象是否已经被初始化,如果是则提示,不是则编译通过?

我个人觉得是完全可以的,intellisense甚至都可以做到。但是如果允许这种行为的话,可能会出现,当你从一个类继承时,你需要沿着继承链向上,判断你需要初始化的父类成员是否已经被他的某个子孙类给初始化了。这显然不是一种好的做法。

而且无论从哪个设计角度,子类初始化父类成员这种越俎代庖的行为都不合理。

至于解决方案,可以对父类的构造函数传参数对其进行初始化。或者结合1)和2)可以推出,在构造函数体里内直接赋值也是可以的


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/382060.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode (合集)合并链表和数组

LeetCode 88. 合并两个有序数组 golang LeetCode 21. 合并两个有序链表 golang 合并两个有序链表并去重 /*** Definition for singly-linked list.* type ListNode struct {* Val int* Next *ListNode* }*/ func mergeTwoLists(list1 *ListNode, list2 *ListNode) *…

一些好的习惯

无论你是业余的还是专业的程序员,正确的编程风格,不但有助于提升软件产品的功能,还可以明显减少软件灾难的产生。今天,我们就来探讨一下有助于我们获取更佳编程风格的一些最好的规则。代码的可读性至上代码要能可阅读和可理解&…

循环链表的反转

206. 反转链表 func reverseList(head *ListNode) *ListNode {if head nil || head.Next nil {return head}p : reverseList(head.Next)head.Next.Next headhead.Next nilreturn p }循环链表的反转 func reverse(head, key *ListNode) *ListNode {if head.Next key {ret…

英语“作弊”技巧!

和大家分享个更精辟的 无须复习,只要十天英语四级就能过!!!方法让你喷血!!怕以后找不到!!! 1、听力,有三种题型,dialogue(十个对话),passage(三个短文),compo…

程序猿不能错过的十部电影

不同的行业领域中很多时候都分享着共同的思想和理念。比如,大量的计算机编程中涉及到的概念都被运用到了电影里。有些概念出现在电影里后变得如此之酷,甚至反过来能帮助我们程序员更好的理解这些概念。下面就是小编最喜欢的10大电影,它们都在…

Redis运维和开发学习目录

Redis运维和开发学习笔记-全书思维导图 Redis运维和开发学习笔记(1) Redis简介 Redis运维和开发学习笔记(2) redis持久化 Redis运维和开发学习笔记(3)redis搭建集群 Redis运维和开发学习笔记(4) Redis参数意义 Redis运维和开发学习笔记(5) 主从复制和sentinel哨兵模式 Re…

刘汝佳训练指南——数论专题知识点总结:

数论是一个神奇的东西,各种结论都很经典,有些懂,有些自己还不是很懂。接下来就一个一个的介绍吧。第一、素数,素数本身就是一个很让人惊奇的数,因为它代表的是唯一,自己就有连个因数,一个是1&am…

第一次训练赛的相关总结和教训!

没有想到时间会不够用!这是来到这里的真实感受,每天不停歇地看电脑,资料,刷题!几乎没有停下过,有点喘不过气来,不过身体却有一种莫名的兴奋! 不喜欢拖拉的人,可自己又总是…

goland中grpc的安装

go modules https://github.com/goproxy/goproxy.cn/blob/master/README.zh-CN.md go env -w GO111MODULEongo env -w GOPROXYhttps://goproxy.cn,direct安装 gRPC 网络环境允许的同学安装 gRPC 非常方便,直接执行以下命令即可安装完成: go get -u -v…

uva11029 - Leading and Trailing

11029 - Leading and TrailingTime limit: 3.000 seconds http://uva.onlinejudge.org/index.php?optioncom_onlinejudge&Itemid8&category115&pageshow_problem&problem1970Apart from the novice programmers, all others know that you can’t exactly rep…

goland远程调试Docker

开发环境 goland windows10 Docker centos IP:123.57.43.91 操作原理及流程 goland通过tcp/8080(应该选取2375,登录阿里云开启这个端口,这里临时采用)端口与docker-host通信, 发送docker指令,然后让linux执行,通过d…

博客同步测试

该博客通过word发布!

gorm踩的坑

gorm的那些坑 1. db.SingularTable(true) 在Gorm中,表名是结构体名的复数形式,列名是字段名的蛇形小写。即,如果有一个user表,那么如果你定义的结构体名为:User,gorm会默认表名为users而不是user。 db.S…

Go 语言实现 23 种设计模式(修饰器)

修饰器 修饰器模式就是在不改变对象内部结构的情况下,动态扩展它的功能。 Example_one type Object func(string) stringfunc Decorate(fn Object) Object {return func(base string) string {ret : fn(base)ret ret " and Tshirt"return ret} }func…

紫书的训练计划——一点点来,坚持到底!

先做 第10章3 数论的一点补充。然后趁热温习 10.1 和10.2 (可能会有重的题目) (期望,概率的题目还要过段时间回来补坑)然后 第7、8.1,8.2 章做暴力求解和高效算法(可以适当的加快步伐&#…

Go 语言实现 23 种设计模式 单例模式

Go 语言实现 23 种设计模式 单例模式 单例模式 单例模式是一种常用的软件设计模式,在使用过程中,单例对象的类只有一个实例。使用单例模式,1 可以节省内存等资源,例如windows操作系统的资源管理器只有一个就够了。2 方便配置管理…

Go 语言实现 23 种设计模式适配器

Go 语言实现 23 种设计模式适配器 将一个类型的接口转换成客户希望的另外一个接口,使原本由于接口不兼容而不能一起工作的类可以一起工作。 Example_one package mainimport "fmt"// Adaptee 适配者 type MyLegacyPrinter struct{}func (l *MyLegacyPr…

go设计模式思维导图

go设计模式思维导图

uva 1610——Party Games

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id51171 题意:给你n个串的集合D,然后求一个长度最短的串s,使得使得s大于等于D中一半的串,又同时小于另一半串。 思路:直接暴力。先对…

链表相加 2. 两数相加

2. 两数相加 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 您可以…