C++类的多重继承
时间:2014-11-07 22:21 点击:次
前面讨论的是单继承,即一个类是从一个基类派生而来的。实际上,常常有这样的情况:一个派生类有两个或多个基类,派生类从两个或多个基类中继承所需的属性。C++为了适应这种情况,允许一个派生类同时继承多个基类,这种行为称为多重继承(multiple inheritance)。
class D: public A, private B, protected C
{
类D新增加的成员
}
D是多重继承的派生类,它以公用继承方式继承A类,以私有继承方式继承B类,以保护继承方式继承C类。D按不同的继承方式的规则继承A、B、C的属性,确定各基类的成员在派生类中的访问权限。
派生类构造函数名(总参数表列): 基类1构造函数(参数表列), 基类2构造函数(参数表列), 基类3构造函数(参数表列)
{
派生类中新增数成员据成员初始化语句
}
各基类的排列顺序任意。
派生类构造函数的执行顺序同样为:先调用基类的构造函数,再执行派生类构造函数的函数体。调用基类构造函数的顺序是按照声明派生类时基类出现的顺序。
[例11.8] 声明一个教师(Teacher)类和一个学生(Student)类,用多重继承的方式声明一个研究生(Graduate)派生类。教师类中包括数据成员name(姓名)、age(年龄)、title(职称)。学生类中包括数据成员name1(姓名)、age(性别)、score(成绩)。在定义派生类对象时给出初始化的数据,然后输出这些数据。
程序运行结果如下:
name: Wang-li
age: 24
sex:f
score: 89.5
title: assistance
wages: 1234.5
由于此程序的目的只是说明多重继承的使用方法,因此对各类的成员尽量简化(例如没有部门、专业、授课名称等项目),以减少篇幅。有了此基础,读者可以举一反三, 根据实际需要写出更复杂的程序。
请注意:由于在两个基类中把数据成员声明为protected,因此可以通过派生类的成员函数引用基类的成员。如果在基类中把数据成员声明为private,则派生类成员函数不能引用这些数据。
有些读者可能已注意到:在两个基类中分别用name和name1来代表姓名,其实这是同一个人的名字,从Graduate类的构造函数中可以看到总参数表中的参数nam分别传递给两个基类的构造函数,作为基类构造函数的实参。现在两个基类都需要有姓名这一项, 能否用同一个名字来代表?大家可以亲自测试一下。实际上,在本程序中只作这样的修改是不行的,因为在同一个派生类中存在着两个同名的数据成员,在派生类的成员函数show中引用name时就会出现二义性,编译系统无法判定应该选择哪一个基类中的name。这就是下一节要讨论的问题。
为了解决这个矛盾,程序中分别用name和name1来代表两个基类中的姓名,这样程序能通过编译,正常运行。但是应该说这是为了通过编译而采用的并不髙明的方法。虽然在本程序中这是可行的,但它没有实用意义,因为绝大多数的基类都是已经编写好的、已存在的,用户可以利用它而无法修改它。解决这个问题有一个好方法:在两个基类中可以都使用同一个数据成员名name,而在show函数中引用数据成员时指明其作用域,如
cout<<"name:"<<Teacher::name<<endl;
这就是惟一的,不致引起二义性,能通过编译,正常运行。
通过这个程序还可以发现一个问题:在多重继承时,从不同的基类中会继承一些重复的数据。如果有多个基类,问题会更突出,所以在设计派生类时要细致考虑其数据成员,尽量减少数据冗余。
声明多重继承的方法
如果已声明了类A、类B和类C,可以声明多重继承的派生类D:class D: public A, private B, protected C
{
类D新增加的成员
}
D是多重继承的派生类,它以公用继承方式继承A类,以私有继承方式继承B类,以保护继承方式继承C类。D按不同的继承方式的规则继承A、B、C的属性,确定各基类的成员在派生类中的访问权限。
多重继承派生类的构造函数
多重继承派生类的构造函数形式与单继承时的构造函数形式基本相同,只是在初始表中包含多个基类构造函数。如派生类构造函数名(总参数表列): 基类1构造函数(参数表列), 基类2构造函数(参数表列), 基类3构造函数(参数表列)
{
派生类中新增数成员据成员初始化语句
}
各基类的排列顺序任意。
派生类构造函数的执行顺序同样为:先调用基类的构造函数,再执行派生类构造函数的函数体。调用基类构造函数的顺序是按照声明派生类时基类出现的顺序。
[例11.8] 声明一个教师(Teacher)类和一个学生(Student)类,用多重继承的方式声明一个研究生(Graduate)派生类。教师类中包括数据成员name(姓名)、age(年龄)、title(职称)。学生类中包括数据成员name1(姓名)、age(性别)、score(成绩)。在定义派生类对象时给出初始化的数据,然后输出这些数据。
- #include <iostream>
- #include <string>
- using namespace std;
- class Teacher//声明类Teacher(教师)
- {
- public://公用部分
- Teacher(string nam,int a, string t)//构造函数
- {
- name=nam;
- age=a;
- title=t;
- }
- void display( )//输出教师有关数据
- {
- cout<<"name:"<<name<<endl;
- cout<<"age"<<age<<endl;
- cout<<"title:"<<title<<endl;
- }
- protected://保护部分
- string name;
- int age;
- string title;//职称
- };
- class Student//定义类Student(学生)
- {
- public:
- Student(char nam[],char s,float sco)
- {
- strcpy(name1,nam);
- sex=s;
- score=sco;
- }//构造函数
- void display1( )//输出学生有关数据
- {
- cout<<"name:"<<name1<<endl;
- cout<<"sex:"<<sex<<endl;
- cout<<"score:"<<score<<endl;
- }
- protected://保护部分
- string name1;
- char sex;
- float
- score;//成绩
- };
- class Graduate:public Teacher,public Student //声明多重继承的派生类Graduate
- {
- public:
- Graduate(string nam,int a,char s, string t,float sco,float w):Teacher(nam,a,t),Student(nam,s,sco),wage(w) { }
- void show( ) //输出研究生的有关数据
- {
- cout<<"name:"<<name<<endl;
- cout<<"age:"<<age<<endl;
- cout<<"sex:"<<sex<<endl;
- cout<<"score:"<<score<<endl;
- cout<<"title:"<<title<<endl;
- cout<<"wages:"<<wage<<endl;
- }
- private: float wage; //工资
- };
- int main( )
- {
- Graduate grad1("Wang-li",24,'f',"assistant",89.5,1234.5);
- grad1.show( );
- return 0;
- }
#include <iostream> #include <string> using namespace std; class Teacher//声明类Teacher(教师) { public://公用部分 Teacher(string nam,int a, string t)//构造函数 { name=nam; age=a; title=t; } void display( )//输出教师有关数据 { cout<<"name:"<<name<<endl; cout<<"age"<<age<<endl; cout<<"title:"<<title<<endl; } protected://保护部分 string name; int age; string title;//职称 }; class Student//定义类Student(学生) { public: Student(char nam[],char s,float sco) { strcpy(name1,nam); sex=s; score=sco; }//构造函数 void display1( )//输出学生有关数据 { cout<<"name:"<<name1<<endl; cout<<"sex:"<<sex<<endl; cout<<"score:"<<score<<endl; } protected://保护部分 string name1; char sex; float score;//成绩 }; class Graduate:public Teacher,public Student //声明多重继承的派生类Graduate { public: Graduate(string nam,int a,char s, string t,float sco,float w):Teacher(nam,a,t),Student(nam,s,sco),wage(w) { } void show( ) //输出研究生的有关数据 { cout<<"name:"<<name<<endl; cout<<"age:"<<age<<endl; cout<<"sex:"<<sex<<endl; cout<<"score:"<<score<<endl; cout<<"title:"<<title<<endl; cout<<"wages:"<<wage<<endl; } private: float wage; //工资 }; int main( ) { Graduate grad1("Wang-li",24,'f',"assistant",89.5,1234.5); grad1.show( ); return 0; }
name: Wang-li
age: 24
sex:f
score: 89.5
title: assistance
wages: 1234.5
由于此程序的目的只是说明多重继承的使用方法,因此对各类的成员尽量简化(例如没有部门、专业、授课名称等项目),以减少篇幅。有了此基础,读者可以举一反三, 根据实际需要写出更复杂的程序。
请注意:由于在两个基类中把数据成员声明为protected,因此可以通过派生类的成员函数引用基类的成员。如果在基类中把数据成员声明为private,则派生类成员函数不能引用这些数据。
有些读者可能已注意到:在两个基类中分别用name和name1来代表姓名,其实这是同一个人的名字,从Graduate类的构造函数中可以看到总参数表中的参数nam分别传递给两个基类的构造函数,作为基类构造函数的实参。现在两个基类都需要有姓名这一项, 能否用同一个名字来代表?大家可以亲自测试一下。实际上,在本程序中只作这样的修改是不行的,因为在同一个派生类中存在着两个同名的数据成员,在派生类的成员函数show中引用name时就会出现二义性,编译系统无法判定应该选择哪一个基类中的name。这就是下一节要讨论的问题。
为了解决这个矛盾,程序中分别用name和name1来代表两个基类中的姓名,这样程序能通过编译,正常运行。但是应该说这是为了通过编译而采用的并不髙明的方法。虽然在本程序中这是可行的,但它没有实用意义,因为绝大多数的基类都是已经编写好的、已存在的,用户可以利用它而无法修改它。解决这个问题有一个好方法:在两个基类中可以都使用同一个数据成员名name,而在show函数中引用数据成员时指明其作用域,如
cout<<"name:"<<Teacher::name<<endl;
这就是惟一的,不致引起二义性,能通过编译,正常运行。
通过这个程序还可以发现一个问题:在多重继承时,从不同的基类中会继承一些重复的数据。如果有多个基类,问题会更突出,所以在设计派生类时要细致考虑其数据成员,尽量减少数据冗余。
顶一下
(1)
33.3%
踩一下
(2)
66.7%
上一篇:C++派生类的析构函数
下一篇:C++多重继承的二义性问题
相关内容:
最新内容
热点内容
- QQ群
-
微信
- 返回首页
- 返回顶部