C++ 多继承

    科技2022-08-10  112

    多继承(多重继承)

    在前面的类继承例子中,基类虽然有多个派生类,但派生类都只有一个基类,称为单继承(Single inheritance)。除此之外,C++也支持多继承(Mutiple inheritance),即一个派生类可以派生自两个以上的多个基类。

    需要注意的是:多继承容易让代码逻辑复杂,思路混乱,中小型项目中较少使用


    要深入多继承的概念,首先重温一下 继承的三种方式:

    公有继承(public),私有继承(private),保护继承(protected) 三种继承方式的说明,如下表所示:


    类多继承的语法:

    多继承的语法很简单,将多个基类用逗号隔开即可,例如已声明了类A,类B和类C,且ABC这三个类都当作基类一起派生一个派生类D,那么可以这样来声明派生类D:

    class D:public A,protected B,private C //基类出现的顺序为 A - B - C { //派生类D的新增成员 };

    以上述代码为例,D是多继承形式的派生类,D类以公有的方式继承A类,以保护的方式继承 B 类,以私有的方式继承 C 类,D类根据不同的继承方式来 获取ABC三个基类的成员,确定ABC三个基类的成员们在派生类中的访问权限。


    多继承下的类构造函数:

    多继承形式下的构造函数和单继承形式基本一致,只要在派生类的构造函数中调用多个基类的构造函数即可,以上述案例的A,B,C,D类为例,派生类D类的构造函数的写法为:

    D::D(D构造器的参数列表):A(A构造器的参数列表),B(B构造器的参数列表),C(C构造器的参数列表) { D构造器的其他操作 }

    注意:🎯 基类们(ABC)的构造函数的在多继承时派生类构造函数中的调用顺序和它们在派生类构造函数中出现的顺序无关,而是取决与声明派生类时,各个基类出现的顺序(继承基类时出现的顺序为A-B-C),即使将D类构造函数写做下面的形式:

    D::D(D构造器的参数列表):C(C构造器的参数列表)A(A构造器的参数列表),B(B构造器的参数列表) { D构造器的其他操作 }

    程序在运行时也是先调用A的构造函数,再调用B类的构造函数,最后再调用C类的构造函数


    多继承情况下的构造函数和析构函数

    class D:public A,protected B,private C //基类出现的顺序为 A - B - C { //派生类D的新增成员 };

    以上述代码为例 程序调用各类的构造函数的顺序为 A-B-C-D,而调用析构函数的顺序为D-C-B-A。这说明多继承形式下析构函数的执行顺序和构造函数的执行顺序是相反的。


    命名冲突

    当两个或多个基类中国有同名成员(例如A,B,C三个基类都有成员函数show())的时候,如果直接访问该成员(派生类D类中调用show函数),就会产生命名冲突,编译器会进行不明确提示,编译器此时不知道该使用哪个基类的成员,这时需要在成员名字的前面加类名和域解析符 “::” ,便可以显式的指明到底使用哪个类的成员,以此消除二义性。

    例如以下代码:

    //基类A class BaseA { public: void show(); }; void BaseA::show() { cout<<"基类A的show"<<m_a<<endl; } //基类B class BaseB { public: void show(); }; void BaseB::show() { cout<<"基类B的show"<<m_a<<endl; } //派生类Derived class Derived: public BaseA, public BaseB { public: void display(); }; void Derived::display() { BaseA::show(); //调用BaseA类的show()函数 BaseB::show(); //调用BaseB类的show()函数 cout<<"派生类Derived的display"<<m_a<<endl; } int main() { Derived obj; obj.display(); 结果为: "基类A的show" "基类B的show" "派生类Derived的display" return 0; }

    多继承的实际应用

    什么时候用到多继承? 只要遇到的问题无法只用一个"是一个"关系来描述的时候,就是多继承出场的时候

    举个例子: 学校里有老师和学生,他们属于person类 从面向对象编程的角度上看,应该创建一个名为person的基类和两个名为Teacher()和Student的子类,后两者都是从 前者继承而来的

    但问题来了,有些学生在上课同时还当助教赚钱该怎么办?此时就存在一种即是老师也是学生的复杂关系:也就是存在着两个"是一个"关系

    我们此时就需要写一个TeachingStudent类让它同时继承Teacher类和Student类,换句话说,就是要使用多继承来解决两个是一个的问题。

    代码演示:

    #include <iostream> #include <string> using namespace std; class Person //todo基类Person 由Teacher类和Student类共同继承 { public: Person(string theName); void introduce();//介绍信息程序 protected: string name; }; class Teacher :public Person //todo既是派生类又是基类的Teacher类 继承Person类,派生TeachingStudent类 { public: Teacher(string theName, string theClass); void teach();//老师授课程序 void introduce();//介绍信息程序 protected: string classes; }; class Student :public Person //todo既是派生类又是基类的Student类 继承Person类,派生TeachingStudent类 { public: Student(string theName, string theClass); void attendClass();//学生上课程序 void introduce();//介绍信息程序 protected: string classes; }; class TeachingStudent :public Student, public Teacher //todo派生类TeachingStudent类 基类为Student和teacher类 { public: TeachingStudent(string theName, string classTeaching, string classAttending); void introduce();//介绍信息程序 }; Person::Person(string theName) //todo基类Person类构造函数 { name = theName; } void Person::introduce()//todo基类Person类介绍程序Person::introduce() { cout << "大家好,我是" << name << "。\n\n"; } //----------------------------------------------------------------------------------------------------- //todo既是派生类又是基类的Teacher类 的构造函数 继承Person类的参数列表 Teacher::Teacher(string theName, string theClass) :Person(theName) { classes = theClass; } //todo既是派生类又是基类的Teacher类 的老师授课程序 Teacher::teach() void Teacher::teach() { cout << name << "教" << classes << "\n\n"; } //todo既是派生类又是基类的Teacher类 的老师介绍程序 Teacher::introduce() void Teacher::introduce() { cout << "大家好,我是" << name << ",我教" << classes << "\n\n"; } //----------------------------------------------------------------------------------------------------- //todo既是派生类又是基类的Student类 的构造函数 继承Person类的参数列表 Student::Student(string theName, string theClass) :Person(theName) { classes = theClass; } //todo既是派生类又是基类的Student类 的学生上课程序 Student::attendClass() void Student::attendClass() { cout << name << "加入" << classes << "学习\n\n"; } //todo既是派生类又是基类的Student类 的学生介绍程序 Student::introduce() void Student::introduce() { cout << "大家好,我是" << name << "我在" << classes << "学习\n\n"; } //----------------------------------------------------------------------------------------------------- //todo派生类TeachingStudent的构造函数 继承基类Teacher和Student的构造函数列表 TeachingStudent::TeachingStudent(string theName, string classTeaching, string classAttending) :Teacher(theName, classTeaching), Student(theName, classAttending) {} //todo派生类TeachingStudent的介绍程序 TeachingStudent::introduce() void TeachingStudent::introduce() { cout << "大家好,我是" << Student::name << "我在教" << Teacher::classes << ","; cout << "同时我在" << Student::classes << "学习\n\n"; } int main() { Teacher teacher("张老师", "奥数班"); Student student("小明", "奥数班"); TeachingStudent teacherstudent("杰克", "英语班", "奥数班"); teacher.introduce(); teacher.teach(); student.introduce(); student.attendClass(); teacherstudent.introduce(); teacherstudent.teach(); teacherstudent.attendClass(); return 0; }

    运行结果:

    Processed: 0.023, SQL: 8