从代码学会多继承
从之前的文章中,学会了继承及单继承的知识,这里来学习一下多继承。对于多继承来说,就是一个子类继承了多个父类。
可以参考单继承的文章,作为补充知识。https://blog.csdn.net/weixin_42078660/article/details/113755197
多继承语法
派生类名::派生类名(参数总表)
:基类名 1(参数表 1),基类名(参数名 2)....基类名 n(参数名 n),
内嵌子对象 1(参数表 1),内嵌子对象 2(参数表 2)....内嵌子对象 n(参数表 n)
{
派生类新增成员的初始化语句;
}
下面我们来根据上诉的格式,实现一个简单的多继承,
class A{
public:
A(int _d) :data(_d){}
void setData(int i)
{
data = i;
}
int data;
};
class B{
public:
B(int _d) :data(_d){}
int getData()
{
return data;
}
int data;
};
class C :public A, public B{
public:
C() :A(2), B(3)
{}
void dis()
{
cout << "A::data: " << A::data << endl;
cout << "B::data: " << B::data << endl;
}
};
int main()
{
C c;
c.dis();
c.setData(100);
cout << c.getData() << endl;
return 0;
}
但是根据我们的测试代码,我们可以知道的是在我们的两个基类中,均有data这个数据成员,当派生类中我们进行多继承的时候,就会同时继承出两个data,这两个data是在不同的作用域下,这时候就会产生数据的冗余情况。
上图就是 代码的执行结果,以及通过vs来查看到C类的内存布局。
为了解决这种数据冗余的问题,这个时候,我们就需要将三角的继承转换成四角继承,提取出一个公共类,通过虚继承的方式,使得每个数据仅存一份。
虚继承的语法
class 派生类名:virtual 继承方式 基类
因此我们就可以将上诉的代码修改成如下的结果:
class M{
public:
M(int _d) :data(_d){}
int data;
};
class A:virtual public M
{
public:
A(int _d) :M(_d){}
void setData(int i)
{
data = i;
}
};
class B :virtual public M
{
public:
B(int _d) :M(_d){}
int getData()
{
return data;
}
};
class C :public A, public B{
public:
C() :A(2), B(3), M(1)
{}
void dis()
{
cout << "A::data: " << A::data << endl;
cout << "B::data: " << B::data << endl;
}
};
int main()
{
C c;
c.dis();
c.setData(100);
cout << c.getData() << endl;
c.dis();
return 0;
}
通过上诉的代码,我们成功的将数据合成了一份,在派生类C中的data只有一份,这时候就不会出现数据冗余的问题了。
虚继承的意义
在虚继承中,提取出来的这个类(M)叫做虚基类,他通过虚继承的方式继承出来了A,B两个类,最后在派生出了C类,使得A,B 两个类在C类中的数据不会出现冗余的情况。
在多继承中,保存共同基类的多份同名成员,虽然有时是必要的,可以在不同的数据成员中分别存放不同的数据,但在大多数情况下,是我们不希望出现的。因为保留多份数据成员的拷贝,不仅占有较多的存储空间,还增加了访问的困难。 为此,c++提供了,虚基类和虚继承机制,实现了在多继承中只保留一份共同成员。
虚基类,需要设计和抽象,虚继承,是一种继承的扩展。