首页 > 编程语言 >C++多继承(多重继承)

C++多继承(多重继承)

时间:2022-11-29 10:24:58浏览次数:58  
标签:多重 BaseB cout BaseA 继承 Derived C++ int public

派生类都只有一个基类,称为单继承(Single Inheritance)。除此之外,C++也支持多继承(Multiple Inheritance),即一个派生类可以有两个或多个基类。

多继承容易让代码逻辑复杂、思路混乱,一直备受争议,中小型项目中较少使用,后来的 JavaC#PHP 等干脆取消了多继承。
多继承的语法也很简单,将多个基类用逗号隔开即可。例如已声明了类A、类B和类C,那么可以这样来声明派生类D:

class D: public A, private B, protected C{
    //类D新增加的成员
}

D 是多继承形式的派生类,它以公有的方式继承 A 类,以私有的方式继承 B 类,以保护的方式继承 C 类。D 根据不同的继承方式获取 A、B、C 中的成员,确定它们在派生类中的访问权限。

多继承下的构造函数

多继承形式下的构造函数和单继承形式基本相同,只是要在派生类的构造函数中调用多个基类的构造函数。以上面的 A、B、C、D 类为例,D 类构造函数的写法为:

D(形参列表): A(实参列表), B(实参列表), C(实参列表){
    //其他操作
}

基类构造函数的调用顺序和和它们在派生类构造函数中出现的顺序无关,而是和声明派生类时基类出现的顺序相同。仍然以上面的 A、B、C、D 类为例,即使将 D 类构造函数写作下面的形式:

D(形参列表): B(实参列表), C(实参列表), A(实参列表){
    //其他操作
}

那么也是先调用 A 类的构造函数,再调用 B 类构造函数,最后调用 C 类构造函数。

下面是一个多继承的实例:
  1. #include <iostream>
  2. using namespace std;
  3. //基类
  4. class BaseA{
  5. public:
  6. BaseA(int a, int b);
  7. ~BaseA();
  8. protected:
  9. int m_a;
  10. int m_b;
  11. };
  12. BaseA::BaseA(int a, int b): m_a(a), m_b(b){
  13. cout<<"BaseA constructor"<<endl;
  14. }
  15. BaseA::~BaseA(){
  16. cout<<"BaseA destructor"<<endl;
  17. }
  18. //基类
  19. class BaseB{
  20. public:
  21. BaseB(int c, int d);
  22. ~BaseB();
  23. protected:
  24. int m_c;
  25. int m_d;
  26. };
  27. BaseB::BaseB(int c, int d): m_c(c), m_d(d){
  28. cout<<"BaseB constructor"<<endl;
  29. }
  30. BaseB::~BaseB(){
  31. cout<<"BaseB destructor"<<endl;
  32. }
  33. //派生类
  34. class Derived: public BaseA, public BaseB{
  35. public:
  36. Derived(int a, int b, int c, int d, int e);
  37. ~Derived();
  38. public:
  39. void show();
  40. private:
  41. int m_e;
  42. };
  43. Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){
  44. cout<<"Derived constructor"<<endl;
  45. }
  46. Derived::~Derived(){
  47. cout<<"Derived destructor"<<endl;
  48. }
  49. void Derived::show(){
  50. cout<<m_a<<", "<<m_b<<", "<<m_c<<", "<<m_d<<", "<<m_e<<endl;
  51. }
  52. int main(){
  53. Derived obj(1, 2, 3, 4, 5);
  54. obj.show();
  55. return 0;
  56. }
运行结果:
BaseA constructor
BaseB constructor
Derived constructor
1, 2, 3, 4, 5
Derived destructor
BaseB destructor
BaseA destructor

从运行结果中还可以发现,多继承形式下析构函数的执行顺序和构造函数的执行顺序相反。

命名冲突

当两个或多个基类中有同名的成员时,如果直接访问该成员,就会产生命名冲突,编译器不知道使用哪个基类的成员。这个时候需要在成员名字前面加上类名和域解析符::,以显式地指明到底使用哪个类的成员,消除二义性。

修改上面的代码,为 BaseA 和 BaseB 类添加 show() 函数,并将 Derived 类的 show() 函数更名为 display():
  1. #include <iostream>
  2. using namespace std;
  3. //基类
  4. class BaseA{
  5. public:
  6. BaseA(int a, int b);
  7. ~BaseA();
  8. public:
  9. void show();
  10. protected:
  11. int m_a;
  12. int m_b;
  13. };
  14. BaseA::BaseA(int a, int b): m_a(a), m_b(b){
  15. cout<<"BaseA constructor"<<endl;
  16. }
  17. BaseA::~BaseA(){
  18. cout<<"BaseA destructor"<<endl;
  19. }
  20. void BaseA::show(){
  21. cout<<"m_a = "<<m_a<<endl;
  22. cout<<"m_b = "<<m_b<<endl;
  23. }
  24. //基类
  25. class BaseB{
  26. public:
  27. BaseB(int c, int d);
  28. ~BaseB();
  29. void show();
  30. protected:
  31. int m_c;
  32. int m_d;
  33. };
  34. BaseB::BaseB(int c, int d): m_c(c), m_d(d){
  35. cout<<"BaseB constructor"<<endl;
  36. }
  37. BaseB::~BaseB(){
  38. cout<<"BaseB destructor"<<endl;
  39. }
  40. void BaseB::show(){
  41. cout<<"m_c = "<<m_c<<endl;
  42. cout<<"m_d = "<<m_d<<endl;
  43. }
  44. //派生类
  45. class Derived: public BaseA, public BaseB{
  46. public:
  47. Derived(int a, int b, int c, int d, int e);
  48. ~Derived();
  49. public:
  50. void display();
  51. private:
  52. int m_e;
  53. };
  54. Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){
  55. cout<<"Derived constructor"<<endl;
  56. }
  57. Derived::~Derived(){
  58. cout<<"Derived destructor"<<endl;
  59. }
  60. void Derived::display(){
  61. BaseA::show(); //调用BaseA类的show()函数
  62. BaseB::show(); //调用BaseB类的show()函数
  63. cout<<"m_e = "<<m_e<<endl;
  64. }
  65. int main(){
  66. Derived obj(1, 2, 3, 4, 5);
  67. obj.display();
  68. return 0;
  69. }
请读者注意第 64、65 行代码,我们显式的指明了要调用哪个基类的 show() 函数。

标签:多重,BaseB,cout,BaseA,继承,Derived,C++,int,public
From: https://www.cnblogs.com/threebody1379/p/16934611.html

相关文章

  • 在Unity中使用C#调用C++动态链接库(DLL)
     在Unity中使用C#调用C++动态链接库(DLL)https://blog.csdn.net/qq_51456342/article/details/125693678 [FNote: 属性页中无C++项时,要先写点代码编译一下,就有了]......
  • 实验5 继承和多态
    实验任务四:pets.hpp:#pragmaonce#include<iostream>#include<string>std::string;usingnamespacestd;classMachinePets{public:MachinePets(constst......
  • 实验五 继承和多态
    task4//pets.hpp#include<iostream>usingnamespacestd;classMachinePets{private:stringnickname;public:MachinePets(conststrings):n......
  • c++_makefile
    关于四个version的思考,既然makefile的使用是为了便捷,从刚开始第一个简版的makefile有什么用,到第二版可以用依赖来抽象出1$(TARGET)和$(OBJ)之间的关系2.o.cpp之间的关......
  • Swift 2023:强调并发、泛型和 C++ 互操作性,开发 Swift 解析器
    AppleSwift团队的一名工程师兼语言工作组成员JohnMcCall在最新发布的一篇博客中介绍了Swift的2023年度计划。“Swift项目中有很多激动人心的工作正在进行,而且很......
  • C++学习------cmath头文件的源码学习06
    函数族定义---双曲函数cosh---计算双曲余弦函数sinh---计算双曲正弦函数tanh---计算双曲正切函数acosh---计算双曲余弦面积asinh---计算双曲正弦面积atanh---计算双曲正切面......
  • C++引用和指针
    1、有时候要想搞清楚一条赋值语句到底是改变了指针的值还是改变了指针所指对象的值不太容易,最好的办法就是记住赋值永远改变的等号左边的对象,例如:*p=0,改变的是p所指对象的......
  • C++ 类this及返回自身对象的引用方式
    这篇文章主要介绍了C++ 类this及返回自身对象的引用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教 +目录this及返回自身对象......
  • C++ 之 宏定义
      宏在C语言中非常重要,但在C++中却无甚大用,普遍的共识:尽量避免使用宏  C++之父Bjarne在《C++ProgrammingLanguage》中写到Avoidmacros   《Eff......
  • 实验五 继承和多态
    pets.hpp源码#include<iostream>#include<string.h>usingnamespacestd;classMachinePets{private:stringnickname;public:MachinePets(co......