多重继承常常被认为是 OOP 中一种复杂且不必要的部分。多重继承面临 crash 的场景并非难以想象,来看下面的例子。

1. 名称冲突

来看以下情况:

如果 Dog 类以及 Bird 类都有一个名为 eat() 的方法,而子类又没有 override 该方法。如果此时调用子类的 eat() 方法,编译器就会报错,指出 eat() 的调用有歧义(不知道是调用从 Dog 类继承而来的 eat() 方法,还是从 Bird 类继承而来的 eat() 方法)。代码如下:

class Dog
{
public:virtual void eat() {};
};class Bird
{
public:virtual void eat() {};
};class DogBird : public Dog, public Bird
{};int main()
{DogBird db;db.eat(); // BUG! Ambiguous call to method eat()return 0;
}/*
编译错误:
[purple@archlinux AAA]$ clang++ aa.cc
aa.cc:21:8: error: member 'eat' found in multiple base classes of different typesdb.eat(); // BUG! Ambiguous call to method eat()^
aa.cc:4:18: note: member found by ambiguous name lookupvirtual void eat() {};^
aa.cc:10:18: note: member found by ambiguous name lookupvirtual void eat() {};^
1 error generated.
*/

解决方法:

#include <iostream>
using namespace std;class Dog
{
public:virtual void eat() {cout << "The Dog has eaten." << endl;};
};class Bird
{
public:virtual void eat() {cout << "The Bird has eaten." << endl;};
};class DogBird : public Dog, public Bird
{};int main()
{DogBird db;static_cast<Dog>(db).eat(); // Slices, calling Dog::eat()db.Bird::eat();             // Calls Bird::eat()return 0;
}/*
Output:
The Dog has eaten.
The Bird has eaten.
*/

为了消除歧义,要么在 DogBird类重写 eat() 方法,要么显示的指明调用的是哪一个父类的版本。

2. 歧义基类

来看以下情况:

虽然可能产生 name ambiguity,但是 C++ 允许这种类型的类层次结构。例如,如果 Animal 类有一个 public 方法 sleep(),那么 DogBird 对象将无法调用这个方法,因为编译器不知道调用 Dog 继承的版本还是 Bird 继承的版本。代码如下:

class Animal
{
public:void sleep(){}
};class Dog : public Animal
{
};class Bird : public Animal
{
};class DogBird : public Dog, public Bird
{
};int main()
{DogBird db;db.sleep();return 0;
}/*
发生编译错误[purple@archlinux ~]$ clang++ aa.cc
aa.cc:25:8: error: non-static member 'sleep' found in multiple base-class subobjects of type 'Animal':class DogBird -> class Dog -> class Animalclass DogBird -> class Bird -> class Animaldb.sleep();^
aa.cc:7:10: note: member found by ambiguous name lookupvoid sleep(){}^
1 error generated.
*/

使用“菱形”类层次结构的最佳方法是将最顶部的类设置为抽象类,所有方法都设置为纯虚方法。由于类只声明方法而不提供定义,在基类中没有方法可以调用,因此在这个层次上就不会产生歧义。代码如下:

#include <iostream>
using namespace std;class Animal
{
public:virtual void sleep() = 0;
};class Dog : public Animal
{
public:virtual void sleep(){cout << "Dog sleep!" << endl;}
};class Bird : public Animal
{
public:virtual void sleep(){cout << "Bird sleep!" << endl;}
};class DogBird : public Dog, public Bird
{
public:// 注意:虽然从语法上来说,DogBird可以不override sleep方法// 但是如此一来,再调用DogBird类的sleep方法时,会分不清是Dog类的还是Bird类的virtual void sleep(){cout << "DogBird sleep!" << endl;}
};int main()
{DogBird db;db.sleep();return 0;
}/*
Output:
DogBird sleep!
*/

小结

我们往往会在定义一个“既是一个事物同时又是另外一个事物”的情况下使用多重继承,然而,实际上遵循这个模式的实际对象很难恰如其分的转换为合适的代码,因此在工程中,我们要尽量避免使用多重继承。

转载于:https://my.oschina.net/abcijkxyz/blog/722772

Cpp多重继承会产生的问题相关推荐

  1. 软件测试系列之单元测试 (转载)

    软件测试系列之单元测试   2009-05-26 作者:Delores 来源:Delores的blog   1 基本理论 整理资料时发现以前给兄弟们灌输的单元测试的一些基本知识,放在这里供大家参考.里 ...

  2. cpp课程设计实验题:定义Staff(员工)类,由Staff分别派生出Saleman(销售员)类和Manager(经理)类,再由Saleman(销售员)类和Manager(经理)类采用多重继承方式派生

    ``定义Staff(员工)类,由Staff分别派生出Saleman(销售员)类和Manager(经理)类,再由Saleman(销售员)类和Manager(经理)类采用多重继承方式派生出新类SaleMa ...

  3. Cpp 对象模型探索 / 多重继承下基类指针释放子类对象的原理说明(虚析构函数的作用)

    源码 #include <iostream>class Base1 { public:virtual void func_1_1(){ std::cout << "B ...

  4. Cpp 对象模型探索 / 多重继承虚函数表分析

    一.源码 #include <iostream>class Base1 { public:virtual void func11(){std::cout << "Ba ...

  5. 多重继承与虚继承编程实验

    多重继承与虚继承编程实验 基本知识 多重继承 多重继承下的类作用域 虚继承 构造函数与虚继承 关于本程序 示例代码 Animal_virtual_baseVers.h virt-inherit.cpp ...

  6. C++ 多重继承之内存存储

    C++ 之多重继承 1. C++中class与struct. 在C++里面,class与struct没有本质的区别,只是class的默认权限是private,而struct则是public.这个概念也 ...

  7. cpp+数据结构+设计模式

    文章目录 O KR cpp # 参考文献 O C++和数据结构不再成为面试短板 KR cpp +++++++++++++++++++++++++ ++++++++++++++++++++++++ ++ ...

  8. C语言中文网-CPP教程

    0.一些知识 const const int * const p; int cosnt * const p; 内存对齐 栈溢出 内存池.池化技术(内存池.线程池) 内存泄露 静态链接库.动态链接库 C ...

  9. java多重继承和多继承_多继承和多重继承

    ------------------siwuxie095 多继承 和 多重继承,两个词差别不大,但是差之毫厘.谬以千里 - 多重继承 如果有这样三个类:人类.士兵类.步兵类,其中:士兵类继承了人类, ...

  10. Review cpp day08

    回顾: Review cpp day01 Review cpp day02 Review cpp day03 Review cpp day04 Review cpp day05 Review cpp ...

最新文章

  1. 温泉关一役历史资料(电影:斯巴达300勇士)
  2. 先用knn对数据集进行预处理再利用神经网络对数据集进行分类_数据挖掘的预处理方法:综述...
  3. read web.config
  4. Hive文件数创建过多的问题
  5. android调用webservice发送header身份验证不成功
  6. Array为什么这样会有错?
  7. 哲学经典名句[zt]
  8. android datepicker 监听,Android编程之DatePicker和TimePicke简单时间监听用法分析
  9. mysql补0操作有什么意义?
  10. OpenStack温哥华峰会Day2日记:大数据带你看峰会热点
  11. C#网络编程(五)----基于TCP的简易多客户端聊天
  12. 商城APP开发关键板块
  13. 编写第一个WOW插件
  14. Tapestry(二):Tapestry基本知识
  15. 【C语言】5个成绩,去掉最高分,去掉最低分,求 平均分
  16. 手机短信验证码开发流程
  17. 薛辽中学2021高考成绩查询,运城:薛辽中学被指众多高中生没有学籍
  18. 排序方法python实现_八字排盘,四柱八字排盘算命,免费排八字,卜易居在线排盘系统...
  19. python怎么做游戏主播_做一名游戏主播是什么样的感受?
  20. 四十 爱是什么 我在软件园的那些日子里

热门文章

  1. 无线路由器服务器连接线,无线路由器连接有线路由器怎么设置?
  2. html超链接本地文件为什么打不开,为什么word文件的本地超链接打不开呢
  3. 使用 html 来创建站点,怎样使用HTML创建免费网站
  4. DigiCert EV证书怎么样 DigiCert EV证书优势分析
  5. bat脚本用默认浏览器打开指定网站
  6. 制表符输出语法分析器的格式
  7. 启动优化之一——启动分析及优化方案
  8. yaml文件的加载使用
  9. SiriKit测试全攻略
  10. Android之自定义一个可播放某一时间段的音乐播放器