gpt4 book ai didi

c++ - 完成虚拟继承

转载 作者:太空狗 更新时间:2023-10-29 22:54:55 25 4
gpt4 key购买 nike

在我的代码中,我有一个基本的菱形图案:

     CommonBase
/ \
/ \
DerivedA DerivedB
\ /
\ /
Joined

它是这样实现的,公共(public)基类有一个默认构造函数和一个带参数的构造函数:

struct CommonBase {
CommonBase() : CommonBase(0) {}

CommonBase(int val) : value(val) {}

const int value;
};

struct DerivedA : public virtual CommonBase {
void printValue() {
std::cout << "The value is " << value << "\n";
}
};

struct DerivedB : public virtual CommonBase {
void printValueTimes2() {
std::cout << "value * 2 is " << value * 2 << "\n";
}
};

struct Joined : public DerivedA,
public DerivedB {
Joined(int val) : CommonBase(val) {
std::cout << "Constructor value is " << val << "\n";
std::cout << "Actual value is " << value << "\n";
}
};

Joined 类使用带参数的构造函数初始化虚拟基础,一切都按预期进行。

但是,当我从 Joined 类派生一个类时,会发生一些奇怪的事情 - CommonBase默认构造函数被调用,除非我也在派生类构造函数中显式初始化 CommonBase

这是使用以下代码演示的:

struct JoinedDerivedA : public Joined {
JoinedDerivedA() : Joined(99) {
printValue();
}
};

struct JoinedDerivedB : public Joined {
JoinedDerivedB() : Joined(99), CommonBase(99) {
printValue();
}
};

int main() {
std::cout << "======= Joined =======\n";
Joined j(99);
j.printValue();
std::cout << "\n=== JoinedDerivedA ===\n";
JoinedDerivedA a;
std::cout << "\n=== JoinedDerivedB ===\n";
JoinedDerivedB b;

return 0;
}

这段代码的输出是

======= Joined =======
Constructor value is 99
Actual value is 99
The value is 99

=== JoinedDerivedA ===
Constructor value is 99
Actual value is 0 // <-- unexpected behaviour
The value is 0

=== JoinedDerivedB ===
Constructor value is 99
Actual value is 99
The value is 99

为什么会这样?是否可以不必再次在派生类中显式初始化公共(public)基类?

下面是ideone上的代码,大家可以自己运行:https://ideone.com/Ie94kb

最佳答案

这在 Initializing bases and members [class.base.init](草案 n4567 中的 12.6.2)中指定。我们可以在 §13 中阅读(强调我的):

(13) In a non-delegating constructor, initialization proceeds in the following order:

(13.1) — First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

(13.2) — Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

(13.3) — Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

(13.4) — Finally, the compound-statement of the constructor body is executed.

[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. —end note ]

这意味着虚拟基类将在之前初始化Joined。所以在DerivedJoinedA中,默认初始化value为0。然后在初始化Joined时,初始化CommonBase 被忽略,因为它已经被初始化并且 value 保持其 0 值。

这就是为什么必须在最派生类中初始化虚拟基类的原因。

关于c++ - 完成虚拟继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53814616/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com