如何调用所有基本类的复制构造函数,以在C 中复制钻石继承中最派生的类对象
How to call copy constructor of all base classes for copying most derived class object in diamond inheritance in C++?
考虑以下代码:
#include<iostream>
using namespace std;
class A
{
public:
A() {cout << "1";}
A(const A &obj) {cout << "2";}
};
class B: virtual A
{
public:
B() {cout << "3";}
B(const B & obj) {cout<< "4";}
};
class C: virtual A
{
public:
C() {cout << "5";}
C(const C & obj) {cout << "6";}
};
class D:B,C
{
public:
D() {cout << "7";}
D(const D & obj) {cout << "8";}
};
int main()
{
D d1;
cout << "n";
D d(d1);
}
程序的输出如下:
1357
1358
因此,对于D d(d1)
行,D
类的复制构造函数被调用。在继承期间,我们需要明确调用基类的复制构造函数,否则仅调用基类的默认构造函数。我知道直到这里。
我的问题:
现在,我想在D d(d1)
执行期间调用所有基类的复制构造函数。为此,如果我在下面尝试 D(const D & obj) : A(obj), B(obj), C(obj) {cout << "8";}
然后我得到这个错误:错误:'class A A::A' is inaccessible within this context
如何解决问题。我想要A
,B
和C
的复制构造函数,当D
的复制构造函数被调用时。这可能是很小的变化,但我没有得到。
首先,让我们更改您的继承,因为当前是私有的:
class B : virtual protected A {...};
class C : virtual protected A {...};
现在,在您的复制构造函数中,明确指定A
和B
和C
的复制构造仪:
class D : protected B, protected C {
D(const D & obj) : A(obj), B(obj), C(obj) {cout << "8";}
};
,输出将根据需要(2468
(。
为什么?
当我们拥有虚拟基类时,必须由最派生的类初始化,否则将存在歧义性的,例如B
还是C
,例如负责A
的构建。
§12.6.2,(13.1(:
在非规定的构造函数中,初始化按以下顺序进行:
- 首先,仅适用于最派生的类(1.8(的构造函数,虚拟基类按照出现在深度优先的左右横向横穿的定向无环图基础类别,其中"从左到右"是派生类基准列表中的基类。
特别是,如果您定义了复制构造函数,并省略了应该调用的复制构造函数列表,则将使用使用默认的构造函数。
您继承了类的方式,所有这些都使用private
继承。
通过将B
的继承从A
和A
从CC_21更改为protected
或public
,您可以解决问题。
class B : protected virtual A
{
...
}
class C : protected virtual A
{
...
}
或
class B : public virtual A
{
...
}
class C : public virtual A
{
...
}
然后更新D
的复制构造函数为:
D(const D & obj) : A(obj), B(obj), C(obj) {cout <<"8";}
ps 对我来说,即使使用private
继承,默认的构造函数也使我感到困惑。
替代解决方案不需要更改类B
或C
的继承修饰符:
class A
{
public:
A() {cout << "1";}
A(const A &obj) {cout << "2";}
};
class B: virtual A
{
public:
B() {cout << "3";}
B(const B & obj) {cout<< "4";}
};
class C: virtual A
{
public:
C() {cout << "5";}
C(const C & obj) {cout << "6";}
};
class D:B,C,virtual A
{
public:
D() {cout << "7";}
D(const D & obj) : A(obj), B(obj), C(obj) {cout << "8";}
};
涉及构造函数的访问检查:来自[class.access]/6
所有访问控件在子句[class.access]中都会影响的能力 从特定实体的声明中访问类成员名称 ... [注意:此访问也适用于隐式引用 构造函数,转换功能和破坏者。 - 终注]
类似地,[class.access]/4
特殊会员功能遵守通常的访问规则。[ 例子: 宣布受构造函数保护可确保仅派生类 朋友可以使用它创建对象。 - 结束示例]
关于基类亚对象的初始化:来自[class.base.init]/9
在非级别的构造函数中,如果给定的潜在构造 Mem-Initializer-ID未指定子对象(包括 没有mem-Initializer-list的情况,因为构造函数 没有ctor intializer(,那么...否则,实体是 默认限制
对于基类子对象,缺乏任何 ctor-initializer 意味着该子对象是默认的。来自[dcl.init]/7
默认initialize t型的对象表示:... 因此选择的构造函数被称为,带有空参数列表, 初始化对象。
因此, ctor-initializer中缺少任何基础是该基础默认限制的请求,这意味着调用默认的构造函数。
缺乏对基类没有什么区别。无论如何,构造函数没有名称,也没有在 ctor-initializer 中命名,它被明确或隐式引用。在这种情况下,标准中没有什么都没有表明不应执行访问控制。
似乎是从无法访问的基类的构造函数都无法调用的,因此您的程序不应编译。
在任何情况下,您都可以将继承从私人更改为受保护,甚至可以在虚拟基类中添加路径:
class D: B, C, virtual A
{
以这种方式,虚拟基类A
仍然是私有的,但是D
可以访问。
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 当从函数参数中的临时值调用复制构造函数时
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 为什么默认复制函数在按值发送参数时不调用?
- 为什么调用复制构造函数而不是移动构造函数?
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- 为用户定义的类正确调用复制构造函数/赋值运算符
- 复制构造函数中的递归调用
- 编译器调用复制运算符而不是移动运算符
- 为什么我的运算符 + 重载尽管是通过引用传递的,但仍调用我的复制构造函数?
- 使用 pybind11 调用 Python 函数时避免复制输入数据
- 为什么没有调用此模板类的复制构造函数?
- 为什么当我做复制和交换习语时不调用我的复制构造函数?
- std::async 如何工作:为什么它会调用这么多次复制/移动?
- 调用类模板中隐式删除的复制构造函数
- 我不知道为什么复制构造函数的调用在 c++ 中不稳定
- push_back std::vector,则重复调用复制构造函数
- 减少复制构造函数调用
- 将参数列表中的元素复制到调用对象中