C++ 多重继承
来源:互联网 发布:梦想云进销存软件 编辑:程序博客网 时间:2024/06/06 02:56
一,C++多重继承
MI描述的是有多个直接基类的类。与单继承一样公有多继承表示也是is-a关系。
class Worker{private: string name;public: void show();};class Singer : public Worker{private: int voice;public: void show();};class Waiter : public Worker{private: int panache;public: void show();};class SingingWaiter : public Singer, public Waiter{public: void show();};
二,多继承的优点与缺点
a,优点:容易实现多个接口。
b,缺点:比较复杂,会产生很多问题。
三,使用多继承带来的问题1 -- 从两个或更多相关基类那里继承同一个类的多个实例
1,从两个或更多相关基类那里继承同一个类的多个实例
class SingingWaiter : public Singer, public Waiter因为Singer与Waiter都继承了一个Worker组件,因此SingingWaiter将包含两个worker组件。此时,如果将派生类对象的地址赋给基类指针,将出现二义性。
SingingWaiter obj;Worker *p = &obj;上面的这种赋值将把指针设置为派生类对象中的基类对象的地址,但obj对象中包含两个Worker对象,有两个地址可供选择,所以应使用类型转换来指定对象。
SingingWaiter obj;Worker *p1 = (Singer *)&obj;Worker *p2 = (Waiter *)&obj;
2, 使用虚基类解决上面的问题
C++引入多重继承的同时引入虚基类,虚基类使得从多个类(它们的基类相同)派生出的类的对象只继承一个基类对象。例如,通过在类声明中使用virtual关键字,可以使Worker被用作Singer与Waiter的虚基类(virtual与public的次序无关紧要)。
class Singer : virtual public Worker{...};class Waiter : virtual public Worker{...};class SingingWaiter : public Singer, public Waiter{...};现在,SingingWaiter对象将包含Worker对象的一个副本。
3,新的构造函数规则
class A{private: int a;public: A(int n):a(n){}};class B : public A{private: int b;public: B(int n, int m):A(n), b(m){}};创建一个B类对象时,B类的构造函数只能调用A类的构造函数,B类的构造函数使用值m,并将值n传递给A类的构造函数。如果Worker是虚基类,则这种自动信息传递将不起作用。例如,对于下面的构造函数:
SingingWaiter(Worker &wk, int p, int v):Waiter(wk, p), Singer(wk, v){}存在的问题是,自动信息传递时,将通过两条不同的途径(Waiter与Singer)将wk传递给Worker对象。为了避免这种冲突,C++在基类是虚的时,禁止信息通过中间类自动传递给基类。因此上述构造函数将初始化panache与voice,但wk参数中的信息将不会传递给子对象Waiter。然而,编译器必须在构造派生类对象之前构造基类对象组件。在上述情况下,编译器将使用Worker的默认构造函数。如果不希望使用默认构造函数来构造虚基类对象,则需要显示调用所需的基类构造函数。因此,构造函数应该是这样的。
SingingWaiter(Worker &wk, int p, int v):Worker(wk), Waiter(wk, p), Singer(wk, v){}上面的代码显示调用Worker类的构造函数,这种做法是合法的,对于虚基类。但是对于非基类,则是非法的。如果是非基类,在SingingWaiter中只能调用Waiter与Singer的构造函数。
四,使用多继承带来的问题2 -- 函数调用的二义性
1,多继承导致的函数调用二义性
例如,SingingWaiter类可能从Singer与Waiter类哪里继承了两个不同的show()函数。
SingingWaiter obj;obj.show();对于单继承,如果没有重新定义show函数,则将使用最近祖先中的定义。而在多重继承中,每个直接祖先都有一个show函数,这将导致函数调用二义性。
2,使用作用域解析运算符来澄清编程者的意图
SingingWaiter obj;obj.Singer::show();obj.Waiter::show();更好的方法是在SingingWaiter中重新定义show,并指出要使用哪个show。
void SingingWaiter::show(){ Singer::show();}
3,对于单继承,让派生类方法调用基类方法是可以的,然而这种递增方法对SingingWaiter无效。
下面的做法忽略了Waiter组件。
void SingingWaiter::show(){ Singer::show();}
通过同时调用Waiter版本的show函数来弥补。
void SingingWaiter::show(){ Singer::show(); Waiter::show();}然而,这样做将显示Worker类对象信息两次,因为Singer::show()与Waiter::show()都调用了Worker::show()。要解决上面的问题,可以使用模块化方法,而不是递增方式,即提供一个只显示Worker组件的方法,一个只显示Singer组件的方法,一个只显示Waiter组件的方法。
void Worker::data(){ cout<<"Name: "<<name<<endl; cout<<"ID: "<<id<<endl;}void Waiter::Data(){ cout<<"Panache: "<<panache<<endl;}void Singer::Data(){ cout<<"voice: "<<voice<<endl;}void SingingWaiter::Data(){ Singer::Data(); Waiter::Data();}void SingingWaiter::show(){ Worker::Data(); Data();}
0 0
- (C++)多重继承
- C++--多重继承
- C++-继承:多重继承 && 虚拟继承
- C++【多重继承和虚继承】
- C++】多重继承,救世主还是鸡肋
- C++_Primer_chapter17 3.多重继承与虚继承
- 多重继承
- 多重继承
- 多重继承
- 多重继承
- 多重继承
- 多重继承
- 多重继承
- 多重继承
- 多重继承
- 多重继承
- 多重继承
- 多重继承
- Mac安装Brew
- java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/JsonProcessingExc异常
- 学生信息管理系统
- Error: "ssdk_instapager_login_html" is not translated in "en" (English) [MissingTranslation]
- 把2个有序数组合并成1个有序数组
- C++ 多重继承
- Session详解
- xgboost0.7的编译安装
- jQuery实现滚动效果
- NO.95 Jenkins管理员工具之:干掉无用的本地workspace(Java版)
- 分页复用代码【Page类、JSP显示页面】
- maven报错
- Mysql command list
- book