前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【C++】继承 ⑫ ( 继承的二义性 | virtual 虚继承 )

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

作者头像
韩曙亮
发布2023-10-27 16:10:07
1440
发布2023-10-27 16:10:07
举报

一、继承的二义性


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

A 类 是 父类 ,

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

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

在这里插入图片描述
在这里插入图片描述

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

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

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

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

代码如下 :

代码语言:javascript
复制
#include "iostream"
using namespace std;

class A {
public:
	int x;
};

// 子类 B 继承了父类 A 的 x 成员
class B : public A {
public:
	int y;
};

// 子类 C 继承了父类 A 的 x 成员
class C : public A {
public:
	int z;
};

// D 多继承 B 和 C 
// 分别从 B 和 C 各自继承一个来自 A 的成员 x
class D : public B, public C {
public:
	int k;
};

2、继承中的二义性报错

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

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

代码语言:javascript
复制
	// 定义 D 类对象 d
	D d;

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

完整报错信息 :

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

3、完整代码示例

代码示例 :

代码语言:javascript
复制
#include "iostream"
using namespace std;

class A {
public:
	int x;
};

// 子类 B 继承了父类 A 的 x 成员
class B : public A {
public:
	int y;
};

// 子类 C 继承了父类 A 的 x 成员
class C : public A {
public:
	int z;
};

// D 多继承 B 和 C 
// 分别从 B 和 C 各自继承一个来自 A 的成员 x
class D : public B, public C {
public:
	int k;
};

int main() {

	// 定义 D 类对象 d
	D d;

	// 访问继承自 B 类的 y 成员
	d.y = 10;
	// 访问继承自 C 类的 z 成员
	d.z = 20;
	// 访问 D 类自己的成员 k
	d.k = 30;

	// 访问 继承自 A 类的 x 成员出现二义性
	// 报错 error C2385: 对“x”的访问不明确
	//d.x = 40;
	
	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
}

执行结果 :

在这里插入图片描述
在这里插入图片描述

二、virtual 虚继承


1、虚继承引入

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

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

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

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

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

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

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

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

2、虚继承语法

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

代码语言:javascript
复制
class 子类类名 : virtual 访问限定符 父类类名
{
	// 子类内容
}

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

代码语言:javascript
复制
class A {
public:
	int x;
};

// 子类 B 继承了父类 A 的 x 成员
class B : virtual public A {
public:
	int y;
};

// 子类 C 继承了父类 A 的 x 成员
class C : virtual public A {
public:
	int z;
};

3、代码示例 - 虚继承

代码示例 :

代码语言:javascript
复制
#include "iostream"
using namespace std;

class A {
public:
	int x;
};

// 子类 B 继承了父类 A 的 x 成员
class B : virtual public A {
public:
	int y;
};

// 子类 C 继承了父类 A 的 x 成员
class C : virtual public A {
public:
	int z;
};

// D 多继承 B 和 C 
// 分别从 B 和 C 各自继承一个来自 A 的成员 x
class D : public B, public C {
public:
	int k;
};

int main() {

	// 定义 D 类对象 d
	D d;

	// 访问继承自 B 类的 y 成员
	d.y = 10;
	// 访问继承自 C 类的 z 成员
	d.z = 20;
	// 访问 D 类自己的成员 k
	d.k = 30;

	// 访问 继承自 A 类的 x 成员出现二义性
	// 报错 error C2385: 对“x”的访问不明确
	// 使用 virtual 虚继承后 , 不会报错
	d.x = 40;
	
	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
}

执行结果 :

在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-10-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、场景说明 - 继承的二义性
  • 2、继承中的二义性报错
  • 3、完整代码示例
  • 二、virtual 虚继承
    • 1、虚继承引入
      • 2、虚继承语法
        • 3、代码示例 - 虚继承
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档