45.多继承
1.多继承概念
我们可以从一个类继承,我们也可以能同时从多个类继承,这就是多继承。但是由于多继承是非常受争议的,从多个类继承可能会导致函数、变量等同名导致较多的歧义。
class Base1{
public:
void func1(){ cout << "Base1::func1" << endl; }
};
class Base2{
public:
void func1(){ cout << "Base2::func1" << endl; }
void func2(){ cout << "Base2::func2" << endl; }
};
//派生类继承Base1、Base2
class Derived : public Base1, public Base2{};
int main(){
Derived derived;
//func1是从Base1继承来的还是从Base2继承来的?
//derived.func1();
derived.func2();
//解决歧义:显示指定调用那个基类的func1
derived.Base1::func1();
derived.Base2::func1();
return EXIT_SUCCESS;
}
多继承会带来一些二义性的问题, 如果两个基类中有同名的函数或者变量,那么通过派生类对象去访问这个函数或变量时就不能明确到底调用从基类1继承的版本还是从基类2继承的版本?
解决方法就是显示指定调用那个基类的版本。
例子1:
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS 1
//2022年10月16日21:24:27
#include <iostream>
using namespace std;
class Father1
{
public:
int bmw;
};
class Father1
{
public:
int bmw;
};
class Son:public Father1, public Father2
{
};
void test()
{
Son s;
//s.bmw;//有二义性问题
}
int main()
{
system("pause");
return EXIT_SUCCESS;
}
特点:
1.多继承是一个类有两个以上的父类
2.多继承的问题是,当父类中有同名成员时,子类中会产生二义性问题
2.菱形继承和虚继承
两个派生类继承同一个基类而又有某个类同时继承者两个派生类,这种继承被称为菱形继承,或者钻石型继承。
这种继承所带来的问题:
1.羊继承了动物的数据和函数,鸵同样继承了动物的数据和函数,当草泥马调用函数或者数据时,就会产生二义性。
2.草泥马继承自动物的函数和数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以。
class BigBase{
public:
BigBase(){ mParam = 0; }
void func(){ cout << "BigBase::func" << endl; }
public:
int mParam;
};
class Base1 : public BigBase{};
class Base2 : public BigBase{};
class Derived : public Base1, public Base2{};
int main(){
Derived derived;
//1. 对“func”的访问不明确
//derived.func();
//cout << derived.mParam << endl;
cout << "derived.Base1::mParam:" << derived.Base1::mParam << endl;
cout << "derived.Base2::mParam:" << derived.Base2::mParam << endl;
//2. 重复继承
cout << "Derived size:" << sizeof(Derived) << endl; //8
return EXIT_SUCCESS;
}
上述问题如何解决?对于调用二义性,那么可通过指定调用那个基类的方式来解决,那么重复继承怎么解决?
对于这种菱形继承所带来的两个问题,c++为我们提供了一种方式,采用虚基类。那么我们采用虚基类方式将代码修改如下:
class BigBase{
public:
BigBase(){ mParam = 0; }
void func(){ cout << "BigBase::func" << endl; }
public:
int mParam;
};
class Base1 : virtual public BigBase{};
class Base2 : virtual public BigBase{};
class Derived : public Base1, public Base2{};
int main(){
Derived derived;
//二义性问题解决
derived.func();
cout << derived.mParam << endl;
//输出结果:12
cout << "Derived size:" << sizeof(Derived) << endl;
return EXIT_SUCCESS;
}
以上程序Base1 ,Base2采用虚继承方式继承BigBase,那么BigBase被称为虚基类。
通过虚继承解决了菱形继承所带来的二义性问题。
重点:
1.虚基类
被虚继承的基类叫虚基类
2.菱形继承的问题
两个父类中有祖类中的数据,然后子类会继承两个父类的数据,会产生二义性问题
3.虚继承
父类虚继承祖类,用virtual关键字
4.虚继承的原理
(1)编译给类添加了一个指针,指针指向类似于表的组织,该表记录了该指针距离变量的偏移量
(2)当子类多继承两个父类,那么只有一份成员变量,然后有两个指针,只有一份成员变量,所以不会产生二义性
参考资料
参考资料来源于黑马程序员等