c++ - 在 c++ 中的菱形问题中,为什么我们需要从子类中调用 grand_parent 构造函数?
问题描述
请阅读代码以了解情况。
#include <iostream>
using namespace std;
class one
{
protected:
int x;
public:
one(int a)
{
x=a;
cout << "one cons called\n";
}
void display(void)
{
cout << "x = " << x << endl;
}
~one()
{
cout << "one destroy\n";
}
};
class two : virtual protected one
{
protected:
int y;
public:
two(int a,int b) : one(a),y(b)
{
cout << "two cons called\n";
}
void display(void)
{
one::display();
cout << "y = " << y << endl;
}
~two()
{
cout << "two destroy\n";
}
};
class three : protected virtual one
{
protected:
int z;
public:
three(int a,int b) : one(a),z(b)
{
cout << "Three cons called\n";
}
void display(void)
{
one::display();
cout << "z = " << z << endl;
}
~three()
{
cout << "three destroy\n";
}
};
class four : private two, private three
{
public:
four(int a,int b,int c) :one(a), two(a,b),three(a,c)
{
cout << " four cons called\n";
}
void display(void)
{
one::display();
cout << "y = " << y << endl;
cout << "z = " << z << endl;
}
~four()
{
cout << "four destroy\n";
}
};
int main()
{
four ob(1,2,3);
ob.display();
return 0;
}
如果我替换代码
four(int a,int b,int c) :one(a), two(a,b),three(a,c)
和
four(int a,int b,int c) :two(a,b),three(a,c)
一个错误消息,例如:在我的代码块 ide 中没有调用 'one::one()' 的匹配函数。
如您所见,这是基于菱形问题的代码。其中第一类是祖父类。二级和三级作为父级,四级作为子级。所以我使用 virtual 关键字来避免歧义。我在这里理解的一切,除非一件事。我知道当父类具有参数化构造函数时,我们需要从派生类向该构造函数提供参数。那么为什么需要向构造函数一提供参数,其中类 4 只有 2 个父类,即 2 和 3 。如果我不调用第四类中的构造函数一,代码会给我编译时错误。请解释一下为什么我们需要这样做。
解决方案
层次结构中的virtual
继承one
通过确保只有一个实例one
存储在two
or的子类中来消除基类的存在歧义three
。回想一下,当继承某个类时,派生实例将始终在内部存储基实例 - 因此virtual
继承确保one
inside of的实例two
和three
在继承层次结构中被任何类“覆盖”。
现在的问题是:谁负责初始化这一个one
实例?应该是two
还是three
?显然不是他们两个,因为只有一个实例。你在这里:它总是负责初始化的最派生one
类- 这是有道理的:嵌入基类副本的实例必须初始化它。
four
这就是带有嵌入式基类实例的类层次结构在没有和有four
加virtual
继承的情况下的样子:
+----------+ +----------+
| one | | one |
+----+-----+ +----+-----+
| |
| |
+-------+-----------+ virtual +--------+--------+ virtual
| | | |
| | | |
+--------+-------+ +-------+-------+ +----+----+ +----+----+
| two | | three | | two | | three |
| +------------+ | | +----------+ | +----+----+ +----+----+
| | one | | | | one | | | |
| +------------+ | | +----------+ | +--------+--------+
| => must init! | | => must init! | |
+----------------+ +---------------+ +-------+--------+
| four |
| +------------+ |
| | one | |
| +------------+ |
| => must init! |
+----------------+
你可以这样想这种机制:virtual
继承赋予基类实例virtual
-ness,这包括构造实例-这种责任被传递到层次结构中。
推荐阅读
- ios - 当列表中的值与 SwiftUI 中的先前值不同时,如何仅在列表中显示值
- javascript - 我如何从数据库 INTO html 中回显值
- r - 使用受密码保护的电子表格解压缩多个文件夹
- python - Flask 模板在页面加载时执行 HTML onclick 功能
- node.js - 从电子商务平台的搜索结果中抓取 Nodejs 网页
- reactjs - 即使在使用 Hooks 刷新 ReactJS 后也能获取最后一个状态
- google-apps-script - 仅当 4 个不同列上的值为真时,Google 工作表脚本才用复选框替换真值
- python-3.x - django无需插件即可上传多个文件
- ruby - NameError - 统一常量 - 仅在生产中
- ios - iOS渐变填充文字动画