c++隐式和显式继承构造函数调用
C++ implicit and explicit inheritance constructor calls
我有一个关于隐式和显式调用基构造函数的问题。如果我们有一个这样的类层次结构:
class Person{
protected:
std::string m_name;
public:
Person(std::string& _name) : m_name(_name){std::cout << "A person is being constructed." << std::endl;}
};
class Baby : public Person{
private:
int m_no_of_nappies;
public:
Baby(std::string& _name, int& _no_of_nappies) : m_no_of_nappies(_no_of_nappies), Person(_name) {std::cout << "A baby is being constructed." << std::endl ;}
};
根据我的课堂笔记,主要是对'Baby'的调用,如下所示:
std::string babyname = "Robert";
int nappies = 5;
Baby baby(babyname, nappies);
导致以下情况发生:
- 当在Baby的初始化列表中显式调用Person时:Baby的初始化列表被调用,并且
no_of_nappies
被初始化。 接下来,调用Person的构造函数并调用Person的初始化列表。 - Baby的构造函数体最终被调用。
m_name
初始化然后调用Person的构造函数体这是有意义的,但是,如果对父类的默认构造函数进行了隐式调用,那么该怎么办呢?
class Vehicle{
protected:
int m_no_wheels;
public:
Vehicle() : m_no_wheels(0) { std::cout << "A vehicle is being constructed." << std::endl; }
};
class Bicycle : public Vehicle{
protected:
bool m_is_locked;
public:
Bicycle() : m_is_locked(false) { std::cout << "A bicycle is being constructed." << std::endl; }
};
这是我不太确定的部分。我最好的猜测是,在主程序中调用Bicycle bike;
具有以下效果:
- 从Bike隐式调用Vehicle的默认构造函数。
- 由于vehicle不继承任何东西, vehicle的初始化列表被称为,它将
m_no_wheels
初始化为0
。 - 调用车辆的构造函数体。
- 我们返回到Bicycle和,现在它的初始化列表被称为,将
m_is_locked
初始化为false
。 - Bike的构造函数体被调用
谁能解释一下我在隐含调用背后的推理是否正确?
在我看来,主要的区别在于,对于基构造函数的显式引用,子类的初始化列表总是首先被命中,以便调用该基构造函数——然而,对于隐式调用,最上面的父类的初始化列表总是首先被命中。
谢谢你,非常感谢!
Edit:我特别问如果顺序改变,取决于对父类的隐式或显式调用。
基类和成员的初始化顺序在[class.base]中指定。您可以在这里找到摘要:http://en.cppreference.com/w/cpp/language/initializer_list#Initialization_order
成员初始化式在列表中的顺序无关紧要:初始化的实际顺序如下:
- 如果构造函数是用于派生最多的类,则虚拟基类将按照它们在基类声明的深度优先从左到右遍历中出现的顺序进行初始化(从左到右指基类说明符列表中的出现顺序)
- 然后,直接基类按从左到右的顺序初始化,因为它们出现在该类的基说明符列表
然后,非静态数据成员按照类定义中的声明顺序初始化。- 最后,执行构造函数体
(注意:如果初始化顺序由不同构造函数的成员初始化列表中的外观控制,则析构函数将无法确保析构顺序与构造顺序相反)
初始化顺序在定义任何构造函数之前就已经确定;构造函数初始化列表只影响如何初始化基和成员,而不影响它们初始化的顺序。
因为Person
是Baby
的基,所以它总是在Baby
的成员m_no_of_nappies
之前被初始化。作为Person
初始化的一部分,初始化它自己的成员,然后执行它的构造函数体。在Person
的构造函数体返回后,对m_no_of_nappies
进行初始化。(破坏总是以相反的顺序发生。)Vehicle
同样是Bicycle
的基数,并且首先初始化;由于它没有mem初始化式,因此调用默认构造函数
§12.6.2定义了初始化的方式:
成员初始化式在列表中的顺序无关紧要:实际的初始化顺序如下:
- 如果构造函数是为派生最多的类,虚基类是按照深度优先的顺序初始化的吗基类声明的从左到右遍历(从左到右)指的是在基本规格表中的外观)
- 然后,直接基地类在其中出现时按从左到右的顺序初始化类的基本说明符列表
- 则是非静态数据成员按类定义中的声明顺序初始化。
- 最后,构造函数体被执行(注意:如果初始化顺序的成员初始化项列表中的外观控制不同的构造函数,那么析构函数就不能保证毁灭的顺序与…的顺序相反建设)
对您的案例进行总结(不考虑虚函数):
- 基类按照声明继承的顺序
- 按申报顺序排列的成员
因此构造函数初始化列表中的顺序对不起作用。
在第一种情况下,你在这一点上是错误的:Person
是Baby
的基类,并且在m_no_of_nappies
之前初始化
编辑:你的问题
Baby从它的初始化列表中调用Person,因此第一个被击中的是Baby的初始化列表?
[class.base。/10可能是你正在寻找的:你没有真正"调用"基类构造函数(假设没有委托),它是由编译器在初始化派生对象时为你调用的。
编译器为您设置了一些东西,以帮助保持构造函数和析构函数的正确顺序
忽略初始化项顺序的原因是为了保持构造函数和析构函数调用通常的FIFO顺序。允许两个构造函数使用不同的基和成员初始化顺序,将限制实现使用更动态和更昂贵的策略
摘自https://stackoverflow.com/a/24287946/1938163
最后和
对基类的隐式调用(编译器做的)是在Bicycle的初始化列表之前还是之后完成的?
在第12.6.2节其他成员类初始化之前。
- 如何在 c++ 多重继承中调用父非虚函数?
- 派生类调用使用非继承成员的继承函数
- 从多重继承中的派生类函数调用适当的父类函数
- 为什么当一个模板类继承自另一个模板类时,需要重新指定 typedef 并限定函数调用?
- C 从同一基本模板类覆盖功能,具有多个继承模棱两可的函数调用
- C++ 中的多级继承和调用基构造函数
- 为什么我继承的构造函数调用我的基本默认构造函数
- C 指针在函数调用后的继承中失去价值
- 多重继承析构函数调用他自己和父析构函数?c++
- 没有匹配的函数调用CTOR,多重继承
- C++继承-从构造函数调用重写
- C++中的多个虚拟继承抱怨特定的函数调用
- C++多级继承函数调用
- C++继承的复制构造函数调用
- 在虚拟继承中构造函数调用的顺序是什么
- C++:从全局函数调用继承的成员函数
- 在C++中的多重继承中调用构造函数中的基成员
- 基类指向派生类继承函数调用的指针
- 在简单继承之后调用复制构造函数
- 对可变模板多继承函数调用的访问不稳定