混合基类的虚拟和非虚拟继承 class
Mixing virtual and non-virtual inheritance of a base class
这是代码:
struct Biology
{
Biology() { cout << "Biology CTOR" << endl; }
};
struct Human : Biology
{
Human() { cout << "Human CTOR" << endl; }
};
struct Animal : virtual Biology
{
Animal() { cout << "Animal CTOR" << endl; }
};
struct Centaur : Human, Animal
{
Centaur() { cout << "Centaur CTOR" << endl; }
};
int main()
{
Centaur c;
return 0;
}
此代码打印:
Biology CTOR
Biology CTOR
Human CTOR
Animal CTOR
Centaur CTOR
为什么?
因为我们创建了一个 Centaur
对象,所以我们从构建 Centaur
开始,构建 Human
、Animal
,最后构建 Centaur
(我们从派生越少越派生)。
让我们从Human
开始:
Human
继承自Biology
,所以我们先调用Biology
的构造函数。
现在 Human
的基础 class 已经构造完成,我们终于可以构造 Human
本身了。
但是,Biology
又被构造了!
为什么?幕后发生了什么?
请注意,这完全是有意让 Animal
从 Biology
虚拟继承,同时,它也是有意让 Human
非虚拟继承自 Biology
.
我们正在以错误的方式解决 Dreaded Diamond:人类和动物实际上都应该继承生物学才能使这项工作成功。
我只是好奇。
另请参阅此代码:
struct Biology
{
Biology() { cout << "Biology CTOR" << endl; }
};
struct Human : virtual Biology
{
Human() { cout << "Human CTOR" << endl; }
};
struct Animal : Biology
{
Animal() { cout << "Animal CTOR" << endl; }
};
struct Centaur : Human, Animal
{
Centaur() { cout << "Centaur CTOR" << endl; }
};
int main()
{
Centaur c;
return 0;
}
这里我们Human
实际上继承自Biology
,而Animal
设置为继承"classic way"。
但这一次,输出不同:
Biology CTOR
Human CTOR
Biology CTOR
Animal CTOR
Centaur CTOR
这是因为 Centaur
首先从 Human
继承 ,然后从 Animal
继承 然后 。
如果顺序是相反的,我们会得到与第一个示例中之前相同的结果 - 两个 Biology
实例被连续构造。
这是什么逻辑?
请尝试解释你的方式,我已经检查了很多网站都在谈论这个。不过none好像满足了我的要求。
从输出中可以清楚地看出,两个 Biology
对象被实例化了。那是因为您 只有一个 继承 virtual
。两个基础 class 实例是可怕的钻石问题中歧义的原因,解决方案是(正如我们所知)both 继承 Biology
virtual
.
层次结构回顾:
Biology Biology
| | # one and only one inheritance virtual
Human Animal
\ /
Centaur
好的,让我们牢记这些规则再次阅读输出:
- Base classes 在派生 classes 之前构建。
- Base classes 是按照它们在 base-specifier-list.
中出现的顺序构造的
- 虚拟基础 classes 是在非虚拟基础之前由最派生的 class - see this.
第一个输出 - Animal
virtual
ly 继承自 Biology
:
Biology CTOR # virtual base class inherited from Animal
Biology CTOR # non-virtual base class of Human
Human CTOR # Human itself
Animal CTOR # Animal's virtual base class already constructed
Centaur CTOR
第二个输出 - Human
virtual
ly 继承自 Biology
:
Biology CTOR # virtual base class inherited from Human
Human CTOR # Human's virtual base class already constructed
Biology CTOR # non-virtual base class of Animal
Animal CTOR # Animal itself
Centaur CTOR
更多信息标准段落 ([class.base.init]/10
):
In a non-delegating constructor, initialization proceeds in the
following order:
— 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.
— 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).
...
非虚拟继承是一种排他关系,就像成员资格一样。 class 可以是给定完整对象中另一个 class 的非虚拟基础 class。
这意味着 class 可以覆盖非虚拟基 class 的虚拟函数而不会导致冲突或问题。
构造函数也可以可靠地初始化非虚基。
只有虚拟基可以是一个完整对象的许多间接基的直接基 class。因为可以共享虚拟基础 class,覆盖程序可能会发生冲突。
构造函数可以尝试初始化 ctor-init-list 中的虚拟基子对象,但如果 class 进一步派生,那部分 ctor-init-list 将被忽略。
- 所有从
Biology
虚拟继承的 class 基类共享一个 Biology
基类实例。
- 从
Biology
继承 non-virtually 的所有基础 class 都有一个实例 Biology
.
你在每个类别中都有一个基地,因此你有一个 Biology
的实例由 Human
引入(并且原则上与其他人共享)和一个实例由 [=16= 引入](从未与任何其他基地共享 class)。
这是代码:
struct Biology
{
Biology() { cout << "Biology CTOR" << endl; }
};
struct Human : Biology
{
Human() { cout << "Human CTOR" << endl; }
};
struct Animal : virtual Biology
{
Animal() { cout << "Animal CTOR" << endl; }
};
struct Centaur : Human, Animal
{
Centaur() { cout << "Centaur CTOR" << endl; }
};
int main()
{
Centaur c;
return 0;
}
此代码打印:
Biology CTOR
Biology CTOR
Human CTOR
Animal CTOR
Centaur CTOR
为什么?
因为我们创建了一个 Centaur
对象,所以我们从构建 Centaur
开始,构建 Human
、Animal
,最后构建 Centaur
(我们从派生越少越派生)。
让我们从Human
开始:
Human
继承自Biology
,所以我们先调用Biology
的构造函数。
现在 Human
的基础 class 已经构造完成,我们终于可以构造 Human
本身了。
但是,Biology
又被构造了!
为什么?幕后发生了什么?
请注意,这完全是有意让 Animal
从 Biology
虚拟继承,同时,它也是有意让 Human
非虚拟继承自 Biology
.
我们正在以错误的方式解决 Dreaded Diamond:人类和动物实际上都应该继承生物学才能使这项工作成功。
我只是好奇。
另请参阅此代码:
struct Biology
{
Biology() { cout << "Biology CTOR" << endl; }
};
struct Human : virtual Biology
{
Human() { cout << "Human CTOR" << endl; }
};
struct Animal : Biology
{
Animal() { cout << "Animal CTOR" << endl; }
};
struct Centaur : Human, Animal
{
Centaur() { cout << "Centaur CTOR" << endl; }
};
int main()
{
Centaur c;
return 0;
}
这里我们Human
实际上继承自Biology
,而Animal
设置为继承"classic way"。
但这一次,输出不同:
Biology CTOR
Human CTOR
Biology CTOR
Animal CTOR
Centaur CTOR
这是因为 Centaur
首先从 Human
继承 ,然后从 Animal
继承 然后 。
如果顺序是相反的,我们会得到与第一个示例中之前相同的结果 - 两个 Biology
实例被连续构造。
这是什么逻辑?
请尝试解释你的方式,我已经检查了很多网站都在谈论这个。不过none好像满足了我的要求。
从输出中可以清楚地看出,两个 Biology
对象被实例化了。那是因为您 只有一个 继承 virtual
。两个基础 class 实例是可怕的钻石问题中歧义的原因,解决方案是(正如我们所知)both 继承 Biology
virtual
.
层次结构回顾:
Biology Biology
| | # one and only one inheritance virtual
Human Animal
\ /
Centaur
好的,让我们牢记这些规则再次阅读输出:
- Base classes 在派生 classes 之前构建。
- Base classes 是按照它们在 base-specifier-list. 中出现的顺序构造的
- 虚拟基础 classes 是在非虚拟基础之前由最派生的 class - see this.
第一个输出 - Animal
virtual
ly 继承自 Biology
:
Biology CTOR # virtual base class inherited from Animal
Biology CTOR # non-virtual base class of Human
Human CTOR # Human itself
Animal CTOR # Animal's virtual base class already constructed
Centaur CTOR
第二个输出 - Human
virtual
ly 继承自 Biology
:
Biology CTOR # virtual base class inherited from Human
Human CTOR # Human's virtual base class already constructed
Biology CTOR # non-virtual base class of Animal
Animal CTOR # Animal itself
Centaur CTOR
更多信息标准段落 ([class.base.init]/10
):
In a non-delegating constructor, initialization proceeds in the following order:
— 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.
— 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).
...
非虚拟继承是一种排他关系,就像成员资格一样。 class 可以是给定完整对象中另一个 class 的非虚拟基础 class。
这意味着 class 可以覆盖非虚拟基 class 的虚拟函数而不会导致冲突或问题。
构造函数也可以可靠地初始化非虚基。
只有虚拟基可以是一个完整对象的许多间接基的直接基 class。因为可以共享虚拟基础 class,覆盖程序可能会发生冲突。
构造函数可以尝试初始化 ctor-init-list 中的虚拟基子对象,但如果 class 进一步派生,那部分 ctor-init-list 将被忽略。
- 所有从
Biology
虚拟继承的 class 基类共享一个Biology
基类实例。 - 从
Biology
继承 non-virtually 的所有基础 class 都有一个实例Biology
.
你在每个类别中都有一个基地,因此你有一个 Biology
的实例由 Human
引入(并且原则上与其他人共享)和一个实例由 [=16= 引入](从未与任何其他基地共享 class)。