[C++] 复杂继承关系中的构造函数调用顺序
2018-03-13 11:14
344 查看
虚派生的出现,一定程度上复杂了继承关系。
这篇文章主要是根据C++ Primer 18.3.5小节总结而成的。
废话不多说,让我们直奔主题。
在虚派生中,首先初始化对象的虚基类子部分,然后才初始化直接基类;
如果虚基类自身又有基类,则像往常一样虚基类的构造函数自然也会去调用其基类的构造函数;
如果有多个虚基类,则按照它们在派生列表中的顺序从左到右依次构造;
Q2:一个Final对象中有几个Base子对象、几个Class子对象?
Q3:Class *pc = new Final; 存在的问题?
此外,Final通过一个菱形继承继承了一个虚基类Base,而该虚基类又继承了一个Class;
虚基类Base的存在,使得Final首先去初始化Base()。
当然这里,我们并没有在Final类的初始值列表中明确指出,而是使用了隐式的默认构造;
但是,Base本身有一个Class基类,为此又要先去初始化Class;
接下来的初始化顺序,就跟平时的初始化没什么差别了;只是别忘了还有个Class子对象要初始化;
Q2:一个Final对象中有几个Base子对象、几个Class子对象?
1个Base子对象(虚派生),2个Class子对象;
Q3:Class *pc = new Final; 存在的问题?
由于两个Class子对象的存在,导致二义性问题
这篇文章主要是根据C++ Primer 18.3.5小节总结而成的。
废话不多说,让我们直奔主题。
理论准备
在虚派生中,虚基类是由最底层的派生类直接在其构造函数初始值列表中初始化的,而不是往常那样一层一层递归地初始化;在虚派生中,首先初始化对象的虚基类子部分,然后才初始化直接基类;
如果虚基类自身又有基类,则像往常一样虚基类的构造函数自然也会去调用其基类的构造函数;
如果有多个虚基类,则按照它们在派生列表中的顺序从左到右依次构造;
示例
Q1: 当作用于一个Final对象时,构造函数和析构函数的执行次序分别是?Q2:一个Final对象中有几个Base子对象、几个Class子对象?
Q3:Class *pc = new Final; 存在的问题?
#include <iostream> using namespace std; class Class { public: Class() { cout << "Class()" << endl; } virtual ~Class() { cout << "~Class()" << endl; } }; class Base : public Class { public: Base() { cout << "Base()" << endl; } ~Base() override { cout << "~Base()" << endl; } }; class D1 : virtual public Base { public: D1() { cout << "D1()" << endl; } ~D1() override { cout << "~D1()" << endl; } }; class D2 : virtual public Base { public: D2() { cout << "D2()" << endl; } ~D2() override { cout << "~D2()" << endl; } }; class MI : public D1, public D2 { public: MI() { cout << "MI()" << endl; } ~MI() override { cout << "~MI()" << endl; } }; class Final : public MI, public Class { public: Final() { cout << "Final()" << endl; } ~Final() override { cout << "~Final()" << endl; } }; int main() { { Final f; cout << endl; } Base *pb; Class *pc; MI *pmi; D2 *pd2; // pb = new Class; // pc = new Final; // pmi = pb; pd2 = pmi; }
示例分析
要点
Final对象中有两个Class子对象,其中一个是其直接基类;此外,Final通过一个菱形继承继承了一个虚基类Base,而该虚基类又继承了一个Class;
Solution
Q1: 当作用于一个Final对象时,构造函数和析构函数的执行次序分别是?虚基类Base的存在,使得Final首先去初始化Base()。
当然这里,我们并没有在Final类的初始值列表中明确指出,而是使用了隐式的默认构造;
但是,Base本身有一个Class基类,为此又要先去初始化Class;
接下来的初始化顺序,就跟平时的初始化没什么差别了;只是别忘了还有个Class子对象要初始化;
Q2:一个Final对象中有几个Base子对象、几个Class子对象?
1个Base子对象(虚派生),2个Class子对象;
Q3:Class *pc = new Final; 存在的问题?
由于两个Class子对象的存在,导致二义性问题
相关文章推荐
- 【c++继承】继承关系中派生类对象构造函数和析构函数调用顺序
- C++继承关系中构造函数的调用顺序
- c++学习笔记5,多重继承中派生类的构造函数与析构函数的调用顺序(二)
- C++继承中构造函数调用顺序
- C++ 虚继承对基类构造函数调用顺序的影响
- C++继承中构造函数、析构函数调用顺序及虚析构函数
- C++ 多继承构造函数初始化列表调用顺序
- C++中多重继承构造函数调用的先后顺序
- C++继承中构造函数和析构函数的调用顺序
- C++继承关系中同名函数调用顺序
- C++继承中构造函数、析构函数调用顺序及虚函数的动态绑定
- C++继承中析构函数 构造函数的调用顺序以及虚析构函数
- 理解C++存在继承和组合的对象构造函数调用顺序
- C++继承中构造函数、析构函数调用顺序及虚函数的动态绑定
- C++继承中构造函数、析构函数调用顺序及虚析构函数
- Java中继承关系的构造函数的调用顺序
- C++多重继承中构造函数和析构函数调用顺序举例
- C++继承中析构函数 构造函数的调用顺序以及虚析构函数
- C++ 虚继承对基类构造函数调用顺序的影响
- C++ 虚继承对基类构造函数调用顺序的影响