浅谈多重继承

雨点打透心脏的1/2处 2022-07-24 06:01 268阅读 0赞

继承是c++的一大特性,然而有时候继承能让人看的眼花缭乱,那么今天我们就来谈谈多重继承(Multiple Inheritance)。
MI描述的是有多个直接基类的类,比如有一个基类Worker,这时有两个不同的类Waiter和Singer在这个类的基础上派生出去。代码说话:

  1. class Worker
  2. {
  3. std::string name;
  4. int id;
  5. public:
  6. void Set();//设置数据成员的函数
  7. void Show();//输出函数
  8. virtual ~Worker();
  9. };
  10. class Waiter :public Worker
  11. {
  12. int ap;//Waiter独有的数据成员,appearance的缩写0.0
  13. public:
  14. void Set();
  15. void Show()
  16. };
  17. class Singer :public Worker
  18. {
  19. int rating;//Singer独有的数据成员
  20. public:
  21. void Set();
  22. void Show();
  23. };

似乎这样子没什么问题。但是如果这时候又有一个类SingingWaiter从Waiter和Singer上派生出去,也就是

  1. class SingingWaiter :public Singer, public Waiter//会唱歌的服务员0.0
  2. //注意这里两个前面都要加上public,否则会默认没加的那个是private继承
  3. {
  4. public:
  5. void Set();
  6. void Show();
  7. };

那么问题来了,SingingWaiter中有几个Waiter组件呢?答案是两个。因为它从Waiter类中继承了一个Worker组件,又从Singer类中继承了一个Worker组件。也许有人会问:为什么要继承两个Worker组件,这样有什么用?c++标准难道不能把这种情况定义成只需要继承一个Worker组件吗?这个待会再讲。
其实c++提供了一种解决这种问题的方法:使用虚继承。
虚继承使得从多个基类相同的类中派生出来的对象只继承一个基类的对象。如:

  1. class Waiter :virtual public Worker
  2. {
  3. int ap;
  4. public:
  5. void Set();
  6. void Show()
  7. };
  8. class Singer :public virtual Worker//和virtual public Worker没什么区别
  9. {
  10. int rating;
  11. public:
  12. void Set();
  13. void Show();
  14. };

这样SingingWaiter就只包含一个Worker的组件。
现在再来看为什么c++标准不是按照你想象中的那样来定义这种多重继承,而是要用virtual方法。因为:1.有时可能确实需要基类的多个拷贝;2.将基类作为虚基要求程序完成一些额外的计算,倒不如在需要的时候使用virtual;
但是!即使有了虚继承这一特性,这儿还是有一些小问题。假设原来SingingWaiter成员函数的实现是这样的:

  1. void SingingWaiter::Set()
  2. {
  3. Waiter::Set();
  4. Singer::Set();
  5. }

而Waiter和Singer的Set函数是

  1. void Singer::Set()
  2. {
  3. Worker::Set();
  4. cin >> rating;
  5. }
  6. void Waiter::Set()
  7. {
  8. Worker::Set();
  9. cin >> ap;
  10. }

发现没,我们要调用两次Worker::Set()!
因此,我们要改变SingingWaiter中的Set的策略:使SingingWaiter中的Set函数成为多个组件的集合体,也就是说,在这个集合体中,抽出Worker的Set函数,同时添加上Singer和Waiter的Get函数,Get函数中获取的是他们特有的成员,而不包含共有的成员。

再补充几点:
1.如果使用了虚继承,就不能使用下面这种构造函数:

  1. SingingWaiter(const Worker & wk,int r,int a):Waiter(wk,a),Singer(wk,r){}

原因是这里通过两条路径来将wk传给Worker组件,为了避免这种冲突,c++在是虚的情况下,禁止通过中间类的方式传给基类。
正确的方法是

  1. SingingWaiter(const Worker & wk,int r,int a):Worker(wk),Waiter(wk),Singer(wk,r){}

“`

2.继承有优先性
比如:如果Worker中有一个print函数,Singer中也有一个print函数,那么如果SingingWaiter中如果没有定义print函数的话,调用print时调用的是Singer中的print,而不是Worker中的;但是Singer和Waiter如果同时有print函数,就会产生二义性。

发表评论

表情:
评论列表 (有 0 条评论,268人围观)

还没有评论,来说两句吧...

相关阅读

    相关 c++的多重继承

    一、前言 每个类只继承一个父辈,在现实世界中事情通常是这样的,但是有一些类却代表两个类的合成。例如两用沙发,它是一张床,也是一个沙发。 二、示例代码,用作下面提出问题使用

    相关 C++继承

    关于C++有三大特性:封装、继承和多态 关于继承我们可以实现代码复用减少工作量,在C++里面所谓继承就是在已经存在的类的基础上建立一个新的类。原有的类我们称为基类(父类),新