深入解析C++中类的多重继承
C++类的多继承 class D: public A,private B,protected C{ //类D新增加的成员 }
多继承派生类的构造函数和单继承类基本相同,只是要包含多个基类构造函数。如: D类构造函数名(总参数表列): A构造函数(实参表列),B类构造函数(实参表列),C类构造函数(实参表列){ 新增成员初始化语句 }
派生类构造函数的执行顺序同样为:先调用基类的构造函数,再调用派生类构造函数。基类构造函数的调用顺序是按照声明派生类时基类出现的顺序。 下面的定义了两个基类,BaseA类和BaseB类,然后用多继承的方式派生出Sub类。 #include <iostream> using namespace std; //基类 class BaseA{ protected: int a; int b; public: BaseA(int,int); }; BaseA::BaseA(int a,int b): a(a),b(b){} //基类 class BaseB{ protected: int c; int d; public: BaseB(int,int); }; BaseB::BaseB(int c,int d): c(c),d(d){} //派生类 class Sub: public BaseA,public BaseB{ private: int e; public: Sub(int,int,int); void display(); }; Sub::Sub(int a,int b,int c,int d,int e): BaseA(a,b),BaseB(c,d),e(e){} void Sub::display(){ cout<<"a="<<a<<endl; cout<<"b="<<b<<endl; cout<<"c="<<c<<endl; cout<<"d="<<d<<endl; cout<<"e="<<e<<endl; } int main(){ (new Sub(1,2,3,4,5)) -> display(); return 0; } 运行结果: a=1 b=2 c=3 d=4 e=5 从基类BaseA和BaseB继承来的成员变量,在 Sub::display() 中都可以访问。 当两个基类中有同名的成员时,就会产生命名冲突,这时不能直接访问该成员,需要加上类名和域解析符。 假如在基类BaseA和BaseB中都有成员函数 display(),那么下面的语句是错误的: Sub obj; obj.display();
应该像下面这样加上类名和域解析符: Sub obj; obj.BaseA::display(); obj.BaseB::display();
C++多重继承的二义性问题 如果类A和类B中都有成员函数display和数据成员a,类C是类A和类B的直接派生类。分别讨论下列3种情况。 1) 两个基类有同名成员 代码如下所示: class A { public: int a; void display(); }; class B { public: int a; void display (); }; class C: public A,public B { public: int b; void show(); }; 如果在main函数中定义C类对象cl,并调用数据成员a和成员函数display : C cl; cl.a=3; cl.display();
cl.A::a=3; //引用cl对象中的基类A的数据成员a cl.A::display(); //调用cl对象中的基类A的成员函数display 如果是在派生类C中通过派生类成员函数show访问基类A的display和a,可以不 必写对象名而直接写 A::a = 3; //指当前对象 A::display(); 2) 两个基类和派生类三者都有同名成员 将上面的C类声明改为: class C: public A,public B { int a; void display(); };
C cl; cl.a = 3; cl.display();
有些读者可能对同名覆盖感到不大好理解。为了说明问题,举个例子,例如把中国作为基类,四川则是中国的派生类,成都则是四川的派生类。基类是相对抽象的,派生类是相对具体的,基类处于外层,具有较广泛的作用域,派生类处于内层,具有局部的作用域。若“中国”类中有平均温度这一属性,四川和成都也都有平均温度这一属性,如果没有四川和成都这两个派生类,谈平均温度显然是指全国平均温度。如果在四川,谈论当地的平均温度显然是指四川的平均温度;如果在成都,谈论当地的平均温度显然是指成都的平均温度。这就是说,全国的“平均温度”在四川省被四川的“平均温度”屏蔽了,或者说,四川的“平均温度”在当地屏蔽了全国的“平均温度”。四川人最关心的是四川的温度,当然不希望用全国温度覆盖四川的平均温度。 如果在四川要查全国平均温度,一定要声明:我要查的是全国的平均温度。同样,要在派生类外访问基类A中的成员,应指明作用域A,写成以下形式: cl.A::a=3; //表示是派生类对象cl中的基类A中的数据成员a cl.A::display(); //表示是派生类对象cl中的基类A中的成员函数display 3) 类A和类B是从同一个基类派生的 代码如下所示: class N { public: int a; void display(){ cout<<"A::a="<<a<<endl; } }; class A: public N { public: int al; }; class B: public N { public: int a2; }; class C: public A,public B { public: int a3; void show(){ cout<<"a3="<<a3<<endl; } } int main() { C cl; //定义C类对象cl // 其他代码 } 在类A和类B中虽然没有定义数据成员a和成员函数display,但是它们分别从类N继承了数据成员a和成员函数display,这样在类A和类B中同时存在着两个同名的数据成员a和成员函数display。它们是N类成员的拷贝。类A和类B中的数据成员a代表两个不同的存储单元,可以分别存放不同的数据。在程序中可以通过类A和类B的构造函数去调用基类N的构造函数,分别对类A和类B的数据成员a初始化。 怎样才能访问类A中从基类N继承下来的成员呢?显然不能用 cl.a = 3; cl.display();
cl.N::a = 3; cl. N::display();
cl.A::a=3; cl.A::display(); //要访问的是类N的派生类A中的基类成员 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |