首页 > 编程语言 >【C++】继承 ⑬ ( 虚继承原理 | 虚继承解决继承二义性问题 | 二义性产生的原因分析 )

【C++】继承 ⑬ ( 虚继承原理 | 虚继承解决继承二义性问题 | 二义性产生的原因分析 )

时间:2023-10-29 16:39:42浏览次数:31  
标签:二义性 继承 C++ 调用 父类 public 构造函数



文章目录

  • 一、虚继承原理
  • 1、虚继承解决继承二义性问题
  • 2、二义性产生的原因分析
  • 3、虚继承原理
  • 二、代码示例 - 虚继承原理
  • 1、完整代码示例
  • 2、执行结果







一、虚继承原理




1、虚继承解决继承二义性问题



继承的二义性 : 如果 一个 子类 ( 派生类 ) 继承多个 父类 ( 基类 ) , 这些父类 都继承了 相同的父类 , 那么 子类 访问 父类的父类 中的成员 , 就会产生 二义性 ;

  • 报错 : error C2385: 对“x”的访问不明确 ;


使用 " 虚继承 " 可以解决上述问题 , 子类 继承父类时 , 在 访问限定符 之前使用 virtual 关键字

  • 下面的代码中 A 是父类 ;
  • B 类 和 C 类 虚继承 A 类 , 这样当 某个类 同时 多继承 B 类 和 C 类时 , 访问 A 类中的成员时 , 不会出现 二义性 ;
  • 由于D 类访问 A 中的成员 , 不会产生二义性 ;
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;
};



2、二义性产生的原因分析



二义性产生的原因 :

  • 如果 上述 B 和 C 类 没有 虚继承 A 类 ;
  • 上述 D 对象 创建时 , 会调用 两次 A 的构造函数 ,一次由 C 对象调用 ;
  • 此时 D 对象中就包含了 两个 A 类的 子对象 ;
  • 当 访问 A 类的成员时 , 不知道访问哪个 A 类的成员 , 就出现了二义性 ;


3、虚继承原理



使用 虚继承 后 , 在调用 虚继承 父类 构造函数时 , 只调用一次 ;



构建 D 类对象的 流程 如下 :

  • 先构建 B 类对象 , 调用了一次 A 的构造函数 , 构造了 A 类子对象 ;
  • 再构建 C 类对象 , 发现已经调用了一次 A 的构造函数 , 不会再次构造 第二个 A 类子对象 ;

只有一个 A 类子对象 , 这样就避免了 二义性 的产生 ;






二、代码示例 - 虚继承原理




1、完整代码示例



在下面的代码中 ,

为 A 类 , B 类 , C 类 , D 类 , 都定义一个默认的 无参构造函数 ,

每个构造函数 中打印相关信息 ;

B 类 和 C 类都 虚继承 A 类 ,

最终构建 D 类使 , 发现 A 类的构造函数只调用了一次 , 这样避免了 二义性产生 ;



代码示例 :

#include "iostream"
using namespace std;

class A {
public:
	int x;
	A()
	{
		cout << "A 构造函数" << endl;
	}
};

// 子类 B 继承了父类 A 的 x 成员
class B : virtual public A {
public:
	int y;
	B()
	{
		cout << "B 构造函数" << endl;
	}
};

// 子类 C 继承了父类 A 的 x 成员
class C : virtual public A {
public:
	int z;
	C()
	{
		cout << "C 构造函数" << endl;
	}
};

// D 多继承 B 和 C 
// 分别从 B 和 C 各自继承一个来自 A 的成员 x
class D : public B, public C {
public:
	int k;
	D()
	{
		cout << "D 构造函数" << endl;
	}
};

int main() {

	D d;

	d.x = 10;

	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
}



2、执行结果



执行结果 : A 类的构造函数只调用了一次 , D 类中只有一个 A 类子对象 , 避免了二义性产生 ;

A 构造函数
B 构造函数
C 构造函数
D 构造函数
Press any key to continue . . .

【C++】继承 ⑬ ( 虚继承原理 | 虚继承解决继承二义性问题 | 二义性产生的原因分析 )_1024程序员节


标签:二义性,继承,C++,调用,父类,public,构造函数
From: https://blog.51cto.com/u_14202100/8080487

相关文章

  • 【C++】继承 ⑩ ( 继承机制中的 static 静态成员 | 子类中访问父类静态成员的方法 )
    文章目录一、继承机制中派生类中的static关键字1、子类继承父类静态成员2、父类静态成员访问控制权限的改变3、子类如何访问父类静态成员4、静态成员使用要点二、完整代码示例一、继承机制中派生类中的static关键字1、子类继承父类静态成员子类继承父类静态成员:父类(......
  • 【C++】继承 ⑫ ( 继承的二义性 | virtual 虚继承 )
    文章目录一、继承的二义性1、场景说明-继承的二义性2、继承中的二义性报错3、完整代码示例二、virtual虚继承1、虚继承引入2、虚继承语法3、代码示例-虚继承一、继承的二义性1、场景说明-继承的二义性A类是父类,B类和C类继承A类,是子类,D类多继承B类......
  • c++中重载、重写、隐藏的区别
    重载:同一个函数的不同表现形式。同一个类中;函数原型不同(函数名相同,参数列表即顺序、个数、类型不同);virtual关键字可有可无。 重写:继承关系中,派生类对基类同名函数有不同的表现形式。有继承关系的类;函数原型相同;基类成员函数必须声明为虚函数(virtual)。 隐藏:继......
  • C++ | 每一个C++程序员都应该知道的RAII
    导读:RAII是C++中一种管理资源、避免资源泄漏的惯用法,利用栈的特点来实现。本文较为详细介绍了RAII的原理、使用方法和优点,并且通过实例讲解了RAII在C++STL中的应用,如智能指针和互斥锁等,在最后进行了编程实践。本文适合对C++编程有一定了解的开发者阅读。1.什么是RAIIRAII是R......
  • C和C++的区别
    1.头文件(c++标准头文件都是有命名空间的);2.c++有命名空间,可以解决命名冲突的问题;3.输入与输出1)c++:读入std::cin<<     输出std::cout>>std::endl;2)c:读入:scanf输出:printf4.对空间的开辟和释放c:malloc,calloc,realloc,free......
  • JavaScript ES6 类的继承和构造函数图
        https://www.bilibili.com/video/BV15S4y1N7Mu?p=13&vd_source=f47173c6ece362dfbe9a439ae6addcce   ......
  • C++---数据结构---队列(queue)
    queue容器queue基本概念概念:Queue是一种先进先出(FirstInFirstOut,FIFO)的数据结构,它有两个出口队列容器允许从一端新增元素,从另一端移除元素队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为队列中进数据称为—入队push队列中出数据称为—出队popque......
  • 【C++】继承 ⑧ ( 继承 + 组合 模式的类对象 构造函数 和 析构函数 调用规则 )
    文章目录一、继承+组合模式的类对象构造函数和析构函数调用规则1、场景说明2、调用规则二、完整代码示例分析1、代码分析2、代码示例一、继承+组合模式的类对象构造函数和析构函数调用规则1、场景说明如果一个类既继承了基类,又在类中维护了一个其它类型的成员......
  • Java 静态代码块、代码块、构造方法和多态继承的代码执行顺序
    测试代码importlombok.Getter;publicclassExecutionOrder{{System.out.println("ExecutionOrdercode0");}static{System.out.println("ExecutionOrderstaticcode");}{System.out.println(&......
  • VS and C++ Versions
    VS版本VC版本ToolSet版本MSC版本VisualStudio66 1200VisualStudio20037 1300VisualStudio20058801400VisualStudio20089901500VisualStudio2010101001600VisualStudio2012111101700VisualStudio2013121201800......