C++ 虚拟基类的创建顺序

C++ 虚拟基类的创建顺序,c++,constructor,multiple-inheritance,virtual-inheritance,order-of-execution,C++,Constructor,Multiple Inheritance,Virtual Inheritance,Order Of Execution,我有以下问题: 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 &l

我有以下问题:

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{
A1(){std::cout第一个
A1
源于
B
的(非虚拟)基
AA1
的(虚拟)基的初始化


首先初始化
B
的所有虚拟基,它们依次是
A1
A2
AA2
(初始化
AA2
导致输出
a1aa2
),然后是直接基,其中只有一个,
AA1
(其初始化打印的是
A2 AA1
),最后是类本身,打印
B
。所有虚拟基类都排在第一位,然后只有剩余的非虚拟基类。

B
有三个虚拟基类:
A1
A2
AA2
,它将根据它们的出现顺序对它们进行初始化

您看到的第一个
A1
A2
是虚拟基
A1
A2
的初始化,但是最后一个虚拟基
AA2
有一个非虚拟基
A1
,因此在构建
AA2
之前,您需要构建另一个
A1
,这就是为什么您有另一个
A1
AA2
之前

您可以通过运行以下代码段将其可视化:

#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;
}
您还可以注意到,此代码向您发出警告,因为:

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

您能改进代码格式以便于阅读吗?虚拟类不会被“调用”。您不能“调用类”。相反,对象是初始化的。你是对的,我犯了一个错误。谢谢你的解释。非常感谢。这对我帮助很大。我一直在努力理解这个虚拟函数。它们是我唯一无法理解的,而这个答案对我帮助很大。第一个
A1
实际上来自虚拟基从
AA1
,而不是从
AA2
(实际上是第二个
A1
)的非虚拟基。您可以通过向构造函数添加一个参数来可视化这一点,该参数指示从何处“调用”。@DropFuriosPolaris:我最初的解释是错误的;由于霍尔特的更正,请查看更新的结果。
A1(B)
A2(B)
A1(AA2)
AA2(B)
A2(AA1)
AA1(B)
B()