虚拟基类的创建顺序

Posted

技术标签:

【中文标题】虚拟基类的创建顺序【英文标题】:Virtual base classes order of creation 【发布时间】:2017-07-08 06:41:32 【问题描述】:

我有以下问题:

struct A1 
    A1()  std::cout << "A1, "; 
;

struct A2 
    A2()  std::cout << "A2, "; 
;

struct AA1 : virtual A1,  A2 
    AA1()  std::cout << "AA1, "; 
;

struct AA2 : A1, virtual A2 
    AA2() std::cout << "AA2, "; 
;

struct B : AA1, virtual AA2 
    B()  std::cout << "B "; 
;

int main() 
    B b;

当你运行这段代码时,答案是:

A1 A2 A1 AA2 A2 AA1 B

我想了解第一个 A1 是在哪里创建的。

我知道虚拟类在非虚拟类之前调用​​的规则,但第一个 A1 是困扰我的问题。

【问题讨论】:

您能否改进您的代码格式以便于阅读? 虚拟类不被“调用”。你不能“叫一个班级”。相反,对象被初始化 你是对的,我犯了一个错误。谢谢你的解释。 【参考方案1】:

第一个A1 是由B 的(非虚拟)基AA1 的(虚拟)基的初始化产生的。

首先初始化B的所有虚基,依次为A1A2AA2。 (AA2 的初始化导致输出A1 AA2。)然后是直接基,其中只有一个,AA1(其初始化打印A2 AA1),最后是类本身,打印@987654332 @。首先是所有虚拟基地,然后是其余的非虚拟基地。

【讨论】:

非常感谢。这真的对我有很大帮助。我很难理解这个虚函数。他们是我唯一无法理解的,这个答案对我帮助很大。 第一个A1实际上来自AA1的虚拟基础,而不是来自AA2的非虚拟基础(实际上是第二个A1)。您可以通过向构造函数添加一个参数来显示它们的“调用”位置。 @DropFuriosPolaris:我原来的解释是错误的;请查看更新后的结果,感谢 Holt 的更正。【参考方案2】:

B具有三个虚拟基类:A1A2AA2,并根据它们出现的顺序依次初始化它们。

你看到的第一个A1A2是初始化虚基A1A2,但是最后一个虚基AA2有一个非虚基A1,所以在构造之前AA2,你需要构造另一个A1,这就是为什么你在AA2之前有另一个A1

您可以通过运行以下 sn-p 来可视化这一点:

#include <iostream>

struct A1 
    A1(const char *s)  std::cout << "A1(" << s << ")\n"; 
;

struct A2 
    A2(const char *s)  std::cout << "A2(" << s << ")\n"; 
;

struct AA1 : virtual A1,  A2 
    AA1(const char *s) : A1("AA1"), A2("AA1")  std::cout << "AA1(" << s << ")\n"; 
;

struct AA2 : A1, virtual A2 
    AA2(const char *s) : A1("AA2"), A2("AA2")  std::cout << "AA2(" << s << ")\n"; 
;

struct B : AA1, virtual AA2 
    B() : A1("B"), A2("B"), AA1("B"), AA2("B")  std::cout << "B()\n"; 
;

int main() 
    B b;

这将输出:

A1(B)
A2(B)
A1(AA2)
AA2(B)
A2(AA1)
AA1(B)
B()

您还可以注意到,此代码会向您发出警告,因为:

我在AA2的构造函数中将A1放在了A2之前,但是A2会在A1之前初始化(因为它是一个虚拟基础而A1不是)。 我在B的构造函数中将AA1放在AA2之前,但是AA2会先被初始化(同样的原因)。

【讨论】:

以上是关于虚拟基类的创建顺序的主要内容,如果未能解决你的问题,请参考以下文章

阿里笔试题-派生类构造函数 创建顺序

C++中,建立子类对象的时候,会调用基类的构造函数,

使用虚拟的破坏顺序

笔记2---初始化及类的加载

如何在没有虚方法的情况下创建派生类的基类?

关于类继承的构造与析构调用分析