C++进阶(一):多重继承与虚继承

06/20/2020

多重继承

  • 显示与隐式继承
  • 构造顺序
    • 关系说明
    • 例子二
  • 静态类型和动态类型
  • 多重继承二义性问腿
    • 前缀限定符(::)改正
  • 虚继承
    • 例子
    • 重点
    • 构造顺序

显示与隐式继承

派生类会初始化所有父类的构造函数,如果没有,将会隐式调用默认构造函数,如果父类没有默认构造函数,将会编译错误

class Bear:public ZooAnimal{};
class Panda:public Bear,public Endangered /*<---派生列表!!*/{
	Panda():Endangered()/*<--构造函数初始化列表*/{}    
};
  • Panda 的默认构造函数将会隐式的初始化直接基类Bear的默认构造函数,同时显示初始化Endangerd的构造函数

构造顺序

基类的构造顺序与派生列表中基类中出现顺序保持一致,上述例子

  1. ZooAnimal
  2. Bear
  3. Endangered
  4. Panda

关系说明

Panda的直接基类是Bear和Endangered,Bear的直接基类是ZooAnimal所以先是ZooAnimal,再Bear和Endangered,因为派生列表中Bear在Endangered之前,所以先是Bear,再是Endangered最后Panda类。

例子二

#include 
struct A 
{
	A() 
	{
		std::cout << "A class\n";
	}
};

struct B {

	B() {
		std::cout << "B class\n";
	}
};

struct C :public B, public A /*<-----构造顺序关键在派生列表*/{

	C():A(),B(){
	
		std::cout << "C class\n";
	}
};
int main() {
	C c;   // B,A,C 的构造顺序
	return 0;
}

注意1:析构的顺序和构造的顺序相反
注意2:只有当派生类使用的是合成版本的拷贝、移动或赋值成员时,才会自动对其基类部分执行这些操作

静态类型和动态类型

指针和引用的静态类型决定我们能够使用哪些成员,本质就是类定义完自己的数据成员和函数之后,只能使用自己的和从别人那边继承过来的东西,你不能调用派生类独有的数据成员和函数。动态类型说明符virtual,表示你可以调用派生类的函数,但是这个函数其实你自己也有一个版本,但是派生类重写了一个自己的版本,不是派生类独有函数,这是多态表现

多重继承二义性问腿

二义性问题会引发编译错误,再VS 2019中报 “E0266 “C::x” is ambiguous “和”C2385 ambiguous access of ‘x’“

前缀限定符(::)改正

例子

struct A 
{	
	int x=3;
	void print(int d);
};

struct B {
	int x = 4;
	void print();
};
struct C :public B, public A {
	C() 
	{
		std::cout << x;  //改正为A::x 或者B::x ,前缀限定符
		print(); //<----第二种二义性错误,尽管形参不同,但是名字相同
	}
};

注意:先查找名字后进行类型检查,所以报错报的名字错误

虚继承

派生类间接继承多个相同的父类,默认情况下,派生类中含有继承链上每个类对应的子部分,这就会引发派生类包含对各子对象,随意为类省内存,同时为了共享我们使用虚继承

例子

使用书上的一个例子讲述:
C++进阶(一):多重继承与虚继承_第1张图片

Panda直接继承Bear,Raccoon和Endangered,但是间接继承了ZooAnimal两次,所以这里可以使用虚继承

//virtual public 顺序无所谓
class Raccoon:public virtual ZooAnimal{};
class Bear:virtual public Bear{}
class Panda:public Raccoon,public Bear,public Endangered{};

注意:虚继承不影响派生类本身,而是影响派生类的子类,所以这里影响了Panda类

重点

在虚派生中,虚基类是由最底层的派生类初始化的。
例子:

class Raccoon:public virtual ZooAnimal{};
class Bear:virtual public Bear{}
class Panda:public Raccoon,public Bear,public Endangered
{
	//显示初始化
	Panda():ZooAnimal(),Raccoon(),Bear(),Endangered //最底层Panda来初始化ZooAnimal,尽管不是直接基类
	{
	}
};

注意:任何情况下,对象都会变为最底层的类,所以说如果有虚继承,最好每一个类都初始化虚继承的类

Panda panda; //最底层为panda
Bear bear; //这个对象最底层变为Bear了

构造顺序

观察派生列表,先找虚继承先构造,如果有多个虚继承,就按照顺序完成虚继承部分,再接着按照普通顺序下去

  1. ZooAnimal
  2. Raccoon
  3. Bear
  4. Endangered
  5. Panda

C++ Primer 第五版 第十八章讲述了本章内容

你可能感兴趣的:(C++,进阶,c++,虚继承,多重继承)