【C++】继承 ⑫ ( 继承的二义性 | virtual 虚继承 )

我不是女神ヾ 2024-02-20 08:24 220阅读 0赞

文章目录

  • 一、继承的二义性
    • 1、场景说明 - 继承的二义性
    • 2、继承中的二义性报错
    • 3、完整代码示例
  • 二、virtual 虚继承
    • 1、虚继承引入
    • 2、虚继承语法
    • 3、代码示例 - 虚继承

一、继承的二义性


1、场景说明 - 继承的二义性

A 类 是 父类 ,

B 类 和 C 类 继承 A 类 , 是 子类 ,

D 类 多继承 B 类 和 C 类 , 是 孙子类 ;

在这里插入图片描述

假如 A 类中有 成员变量 x ,

则 子类 B 类 和 C 类 都会继承该 成员变量 x ,

D 类 多继承 B 类 和 C 类 , 会 分别从 B 和 C 各自 继承一个 成员变量 x ;

D 类中 , 从 B , C 两个父类中继承自 爷爷类 A 的成员变量 , 会出现二义性 ;

代码如下 :

  1. #include "iostream"
  2. using namespace std;
  3. class A {
  4. public:
  5. int x;
  6. };
  7. // 子类 B 继承了父类 A 的 x 成员
  8. class B : public A {
  9. public:
  10. int y;
  11. };
  12. // 子类 C 继承了父类 A 的 x 成员
  13. class C : public A {
  14. public:
  15. int z;
  16. };
  17. // D 多继承 B 和 C
  18. // 分别从 B 和 C 各自继承一个来自 A 的成员 x
  19. class D : public B, public C {
  20. public:
  21. int k;
  22. };

2、继承中的二义性报错

如果强行使用 对象.x 访问继承自 A , 会报错 error C2385: 对“x”的访问不明确 ;

定义 D 类的对象 d , 如果访问 继承自 A 类的 x 成员 , 则会出现二义性 ;

  1. // 定义 D 类对象 d
  2. D d;
  3. // 访问 继承自 A 类的 x 成员出现二义性
  4. // 报错 error C2385: 对“x”的访问不明确
  5. d.x = 40;

完整报错信息 :

  1. 1>------ 已启动生成: 项目: HelloWorld, 配置: Debug Win32 ------
  2. 1>Test.cpp
  3. 1>Test.cpp(41,6): error C2385: 对“x”的访问不明确
  4. 1>Test.cpp(41,6): message : 可能是“x”(位于基“A”中)
  5. 1>Test.cpp(41,6): message : 也可能是“x”(位于基“A”中)
  6. 1>已完成生成项目“HelloWorld.vcxproj”的操作 - 失败。
  7. ========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 ==========

3、完整代码示例

代码示例 :

  1. #include "iostream"
  2. using namespace std;
  3. class A {
  4. public:
  5. int x;
  6. };
  7. // 子类 B 继承了父类 A 的 x 成员
  8. class B : public A {
  9. public:
  10. int y;
  11. };
  12. // 子类 C 继承了父类 A 的 x 成员
  13. class C : public A {
  14. public:
  15. int z;
  16. };
  17. // D 多继承 B 和 C
  18. // 分别从 B 和 C 各自继承一个来自 A 的成员 x
  19. class D : public B, public C {
  20. public:
  21. int k;
  22. };
  23. int main() {
  24. // 定义 D 类对象 d
  25. D d;
  26. // 访问继承自 B 类的 y 成员
  27. d.y = 10;
  28. // 访问继承自 C 类的 z 成员
  29. d.z = 20;
  30. // 访问 D 类自己的成员 k
  31. d.k = 30;
  32. // 访问 继承自 A 类的 x 成员出现二义性
  33. // 报错 error C2385: 对“x”的访问不明确
  34. //d.x = 40;
  35. // 控制台暂停 , 按任意键继续向后执行
  36. system("pause");
  37. return 0;
  38. }

执行结果 :

在这里插入图片描述

二、virtual 虚继承


1、虚继承引入

在多继承中 , 如果一个类继承了多个含有相同基类的派生类 , 就会产生菱形继承结构 ;

这种情况下 , 可能会出现多个不同的基类实例 , 导致重复定义和二义性 ;

为了应对上述 继承的二义性 问题 ,

C++ 语言 使用 “ 虚继承 “ 解决 继承中的 二义性问题 ;

C++ 中的 “ 虚继承 “ 是一种解决 多继承 带来的 菱形问题(diamond problem)的技术 ;

虚继承的目的是 确保每个基类只被继承一次 , 从而避免 重复定义 和 二义性等问题 ;

虚继承 通过在 派生类 中使用关键字 virtual 来指示基类应该被虚继承 , 虚继承确保了每个基类只被继承一次 , 从而避免了重复定义和二义性 ;

在 C++ 中,使用虚继承的语法是在基类列表中使用 virtual 关键字 ;

2、虚继承语法

虚继承语法 : 在 继承的 访问限定符 之前 , 添加 virtual 关键字 , 将该继承行为定义为 “ 虚继承 “ ;

  1. class 子类类名 : virtual 访问限定符 父类类名
  2. {
  3. // 子类内容
  4. }

下面的 B 类 和 C 类 , 就是 虚继承 类 A ;

  1. class A {
  2. public:
  3. int x;
  4. };
  5. // 子类 B 继承了父类 A 的 x 成员
  6. class B : virtual public A {
  7. public:
  8. int y;
  9. };
  10. // 子类 C 继承了父类 A 的 x 成员
  11. class C : virtual public A {
  12. public:
  13. int z;
  14. };

3、代码示例 - 虚继承

代码示例 :

  1. #include "iostream"
  2. using namespace std;
  3. class A {
  4. public:
  5. int x;
  6. };
  7. // 子类 B 继承了父类 A 的 x 成员
  8. class B : virtual public A {
  9. public:
  10. int y;
  11. };
  12. // 子类 C 继承了父类 A 的 x 成员
  13. class C : virtual public A {
  14. public:
  15. int z;
  16. };
  17. // D 多继承 B 和 C
  18. // 分别从 B 和 C 各自继承一个来自 A 的成员 x
  19. class D : public B, public C {
  20. public:
  21. int k;
  22. };
  23. int main() {
  24. // 定义 D 类对象 d
  25. D d;
  26. // 访问继承自 B 类的 y 成员
  27. d.y = 10;
  28. // 访问继承自 C 类的 z 成员
  29. d.z = 20;
  30. // 访问 D 类自己的成员 k
  31. d.k = 30;
  32. // 访问 继承自 A 类的 x 成员出现二义性
  33. // 报错 error C2385: 对“x”的访问不明确
  34. // 使用 virtual 虚继承后 , 不会报错
  35. d.x = 40;
  36. // 控制台暂停 , 按任意键继续向后执行
  37. system("pause");
  38. return 0;
  39. }

执行结果 :

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,220人围观)

还没有评论,来说两句吧...

相关阅读