1、3.1 类的诞生 3.2 类的声明和对象的定义 3.4 类的成员及特征 3.4 继承与派生类 3.5 多态性与虚函数 3.6 运算符重载 3.7 输入/输出流库,第3讲 C+面向对象程序设计,Visual C+ 程序设计,Visual C+ 程序设计,第3讲 C+面向对象程序设计,3.4.1 继承与派生的概述 3.4.2 派生类成员的访问属性 3.4.3 派生类的构造函数和析构函数 3.4.4 多继承 3.4.5 虚基类 3.4.6 继承与组合 3.4.7 在软件开发中的重要意义,3.4 继承与派生类,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.1 继承与派生的概述,继承与派生
2、的概念,派生类的声明方式,派生类的构成,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.1 继承与派生的概述,继承与派生的概念,类的关系,类的相互关系而言可以概括为:包容关系(嵌套类)和继承关系。,继 承,包 容,第3讲 C+面向对象程序设计,3.4 继承与派生类,2、基类和派生类,在设计新类时,允许重用某个原有类的所有特征,并在此基础上添加新类的新特征。被重用的原有类称为基类,而新创建的类称为派生类。,3、单继承和多继承,在C+中, 一个子类可由一个父类派生, 也可从多个父类派生, 前者叫单一继承, 后者叫多重继承。,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.1
3、 继承与派生的概述,派生类的声明方式,声明派生类的一般形式如下:,class 派生类名:继承方式 基类名 派生类新增加的成员 ;,继承方式包括: public、private和protected。,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.1 继承与派生的概述,派生类的构成,派生类包括两部分:一部分从基类继承的;一部分是在声明派生类时增加的。,每以部分分别包括数据成员和成员函数。,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.2 派生类成员的访问属性,访问控制: 用于数据的保护和数据封装,C+中,两种类的访问方式:,1) 水平访问实例化使用, 类中声明的访问控制
4、约束访问权限。2)垂直访问继承使用, 子类中的成员函数对父类成员的访问。,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.2 派生类成员的访问属性,在讨论访问属性时,需要考虑以下几种情况:,(1)基类的成员函数访问基类成员?,(2)派生类的成员函数访问派生类的自己增加的成员?,(3)基类的成员函数访问派生类的成员?,(4)派生类的成员函数访问基类的成员?,(5)在派生类外访问派生类的成员?,(6)在派生类外访问基类的成员?,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.2 派生类成员的访问属性,说明:,基类的成员函数只可以访问基类成员, 不能访问派生类的成员;派生类的
5、成员函数访问派生类的成员; 在派生类外可以访问派生类公有成员,但不能访问派生类私有成员;私有数据成员只能被同一类的成员函数访问,公有成员可以被外界访问,保护性成员是有选择性的被访问。,第3讲 C+面向对象程序设计,3.4 继承与派生类,继承的3种方式,公有继承方式(public)(2) 私有继承方式(private)(3) 保护继承方式(protected),3.4.2 派生类成员的访问属性,第3讲 C+面向对象程序设计,3.4 继承与派生类,公有继承方式(public),公有继承的特点是基类的公有成员和保护成员作为派生类 的成员时,它们都保持原有的状态,而基类的私有成员仍 然是私有的。例如:
6、,class CStick : public CMeter int m_nStickNum; / 声明一个私有数据成员public:void DispStick(); / 声明一个公有成员函数 ; / 注意分号不能省略void CStick: DispStick() m_nStickNum = GetPos(); / 调用基类CMeter的成员函数coutm_nStickNum ; ,3.4.2 派生类成员的访问属性,第3讲 C+面向对象程序设计,3.4 继承与派生类,注意: 派生类中或派生类的对象可以使用基类的公有成员(包括保护成员),例如CStick的成员函数DispStick中调用了基类
7、CMeter的GetPos函数,但基类或基类的对象却不可以使用派生类的成员。,3.4.2 派生类成员的访问属性,表1 公有基类在派生类中的访问属性,第3讲 C+面向对象程序设计,3.4 继承与派生类,(2) 私有继承方式(private),私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。,3.4.2 派生类成员的访问属性,表2 私有基类在派生类中的访问属性,第3讲 C+面向对象程序设计,3.4 继承与派生类,#include class CMeter public:CMeter(int nPos = 10) m_nPos = nPos; CMe
8、ter() void StepIt() m_nPos+; int GetPos() return m_nPos; protected:void SetPos(int nPos) m_nPos = nPos; private:int m_nPos; ;class CStick : private CMeter / 从CMeter派生,私有继承 int m_nStickNum; / 声明一个私有数据成员 public:void DispStick(); / 声明一个公有成员函数void SetStick(int nPos) SetPos(nPos);int GetStick() return Ge
9、tPos(); ;,例3.4-1 派生类的私有继承示例。,第3讲 C+面向对象程序设计,3.4 继承与派生类,void CStick: DispStick() m_nStickNum = GetPos(); / 调用基类CMeter的成员函数coutm_nStickNum ; void main() CMeter oMeter(20);CStick oStick; cout“CMeter:“oMeter.GetPos()“,CStick:“oStick.GetStick()endl;oMeter.StepIt(); cout“CMeter:“oMeter.GetPos()“,CStick:“o
10、Stick.GetStick()endl;oStick.DispStick(); ,第3讲 C+面向对象程序设计,3.4 继承与派生类,(3) 保护继承方式(protected),特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。,3.4.2 派生类成员的访问属性,表3 保护基类在派生类中的访问属性,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.2 派生类成员的访问属性,表4 不同继承方式的基类特性和派生类特性,小结1:,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.2 派生类成员的访问属性
11、,表5 派生类中的成员的访问属性,小结2:,注意: 一定要区分清楚派生类的对象和派生类中的成员函数对基类的访问是不同的。例如,(1) 在公有继承时,派生类的对象可以访问基类中的公有成员,派生类的成员函数可以访问基类中的公有成员和保护成员。(2) 在私有继承和保护继承时,基类的所有成员不能被派生类的对象访问,而派生类的成员函数可以访问基类中的公有成员和保护成员。,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.3 派生类的构造函数与析构函数,1、简单派生类的构造函数,派生类的构造函数和析构函数被执行时,基类相应的构造函数和析构函数也会被执行。派生类对象在建立时,先执行基类的构造函数,
12、然后执行派生类的构造函数。但对于析构函数来说,其顺序刚好相反,先执行派生类的析构函数,而后执行基类的析构函数。更需要注意不同派生类构造函数的格式。,2、有子对象的派生类的构造函数,3、有多层派生时的构造函数,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.3 派生类的构造函数与析构函数,1、简单派生类的构造函数,其一般形式为:,派生类构造函数名(总参数列表): 基类构造函数名(参数列表) 派生类中新增数据成员初始化语句;,class Student public:Student (int n, char *nam, char s)num=n; name=nam; sex=s; ;
13、class Student1:public Student public:Student1(int n, char *nam, char s, int a, char *addr):Student(n,nam,s)age=a; address=addr; ;,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.3 派生类的构造函数与析构函数,2、有子对象的派生类的构造函数,其一般形式为:,派生类构造函数名(总参数列表): 基类构造函数名(参数列表),子对象名(参数列表) 派生类中新增数据成员初始化语句; ,类的数据成员包含类对象,此数据成员叫做该类的子对象。,class Student
14、 public:Student (int n, char *nam, char s)num=n; name=nam; sex=s; ; class Student1:public Student public:Student1( int n, char *nam, int n1, char s, char *nam1, char s1, int a, char *addr) :Student(n,nam,s), monitor(n1,nam1,s1)age=a; address=addr;private:Student monitor; ;,第3讲 C+面向对象程序设计,3.4 继承与派生类,
15、3.4.3 派生类的构造函数与析构函数,3、有多层派生时的构造函数,格式与“有子对象派生时的构造函数”同,但要注意,不要列出每一层派生的构造函数,只需写出上一层派生类的构造函数即可。,例3.4-2 多层派生的构造函数。注意:构造函数的书写格式。,#include class Student public:Student(int n,char *nam)num=n;name=nam;void display()cout“num:“numendl;cout“name:“nameendl; protected:int num;char *name; ; class Student1:public S
16、tudent public: Student1(int n,char nam10,int a):Student(n,nam) age=a; ,void show() display();cout“age:“ageendl; protected:int age; ; class Student2:public Student1 public:Student2(int n,char nam10,int a,int s):Student1(n,nam,a)score=s; void show_all() show();cout“score:“scoreendl; protected:int scor
17、e; ; int main() Student2 stud(10010,“Li“,20,92);stud.show_all();return 0; ,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.4 多继承,在类的继承中, C+允许一个派生类继承多个基类,这种行为称为多继承(multiple inheritance)。这种多继承的方式可使派生类具有多个基类的特性,大大提高了程序代码的可重用性。多继承下派生类的定义的格式:class : , ,. ;,其中的继承方式还是前面的三种:public、private和protected。,第3讲 C+面向对象程序设计,3.4 继承与派生类
18、,3.4.4 多继承,class A.class B.class C:public A,private B.派生类C的成员包含了基类A中成员和B中成员以及该类本身的成员。允许一个基类有多个派生类以及从一个基类的派生类中再进行多个层次的派生。,例如:,多继承派生类的构造函数,(总参表) : (参数表1), (参数表2), , (参数表n)派生类中新增数据成员初始化语句;,格式:,例3.4-3 声明一个教师(Teacher)类和一个学生类(Student)类,用多重继承的方式声明一个研究生(Graduate)类,研究生类包括了教师类和学生类的所有成员以及新增了wage(工资)成员。 教师类中包括数
19、据成员name(姓名),age(年龄),title(职称), 学生类中包括数据成员name1(姓名),sex(性别),score(成绩)。在定义派生类对象时给出初始化的数据,并输出这些数据。,#include class Teacher public:Teacher(char *nam,int a, char *t) name=nam;age=a;title=t; protected:char *name;int age;char *title; ; class Student public:Student(char *nam1,char se,float sc) name1=nam1; se
20、x=se;score=sc; protected:char *name1;char sex;float score; ;,class Graduate:public Teacher,public Student public:Graduate(char *nam,int a, char *t,char se,float sc,float w):Teacher(nam, a, t),Student( nam,se, sc), wage(w) void show() cout“name: “nameendl;cout“age: “ageendl;cout“title: “titleendl;cou
21、t“sex: “sexendl;cout“score: “scoreendl;cout“wage: “wageendl; private:float wage; ;int main() Graduate grad(“Yang_Li“,28, “教授“,m,92.5,5500);grad.show();return 0; ,多继承引起的二义性问题,1、两个基类有同名成员,A类,int num1;,void display();,B类,int num1;,void display();,C类,int num1;,void display();,int num1;,void display();,i
22、nt num2;,void show();,基类A 的成员,基类B 的成员,派生类C 的新增成员,多继承引起的二义性问题,2、两个基类和派生类三者都有同名成员,A类,int num1;,void display();,B类,int num1;,void display();,C类,int num1;,void display();,int num1;,void display();,int num1;,void show();,基类A 的成员,基类B 的成员,派生类C 的新增成员,int num2;,多继承引起的二义性问题,3、多个基类从同一个基类派生,class A public:int a
23、;void fun(); ;class B1:public A public:int b1; ;class B2:public A public:int b2; ;class C:public B1,public B2 public:int f( ); ; ,A,B1,B2和C类之间关系如下:,A A a,fun() a,fun() B1 B2b1 b2 C f( ),当C c1;时, 则c1.a和c1.Aa都有二义性。,A类,int a;,void fun();,B1类,int b1;,B2类,int b2;,C类,int B1:a;,int a;,void fun();,int a;,vo
24、id fun();,int B2:a;,int b1;,int b2;,void B1:fun();,int B1:a;,int B2:a;,int b1;,void B2:fun();,int f ();,virtual,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.5 虚基类,虚基类的作用,虚基类的初始化,虚基类的简单应用,虚基类的声明,第3讲 C+面向对象程序设计,3.4 继承与派生类,虚基类的作用,派生类B1和B2都从基类A继承,这时在派生类中就有两个基类A的拷贝。当编译器编译到“cout”a = “aendl;”语句时,因无法确定成员a是从类B1中继承来的,还是从类B2
25、继承来,产生了二义性,从而出现编译错误。解决这个问题的方法之一是使用域作用运算符“ :”来消除二义性。使用虚基类的目的是在多重派生的过程中,使公有的基类在派生类中只有一个拷贝,从而解决上述这种二义性问题。,第3讲 C+面向对象程序设计,3.4 继承与派生类,虚基类的声明,虚基类的声明不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的。 声明虚基类的一般形式为:,calss 派生类名 : virtual 继承方式 基类名,class A ; class B: virtual public A ; class C: virtual public A ;,例如:,虚基类可以在生成一个派
26、生类时作为虚基类,而在生成另一个派生类时不作为虚基类。,第3讲 C+面向对象程序设计,3.4 继承与派生类,虚基类的初始化,C+规定,由虚基类经过一次或多次派生出来的派生类,在其每一个派生类的构造函数的成员初始化列表中必须给出对虚基类的构造函数的调用,如果没有列出,则调用虚基类的默认构造函数。例如:3.4-4出现多次调用虚基类的构造函数时,C+编译系统只执行最后的派生类对虚基类的构造函数的调用。例如:3.4-5,第3讲 C+面向对象程序设计,3.4 继承与派生类,虚基类的简单应用,例3.4-4 在例3.4-3基础上,在Teacher类和Student类之上增加了一个共同的基类Person。如下
27、图。作为人员的一些基本数据都放在Peoson类中,在Teacher类和Student类中再增加一些必要的数据。,#include class Person public:Person( char *nam, char s ,int a) name=nam; sex=s;age=a; protected:char *name;char sex;int age; ; class Teacher: virtual public Person public:Teacher(char *nam,char s,int a, char *t):Person(nam,s,a), title(t) protec
28、ted:char *title; ; class Student : virtual public Person public:Student(char *nam1,char se,int a,float sc):Person(nam1,se,a)score=sc; protected:float score; ;,class Graduate:public Teacher,public Student public:Graduate(char *nam,char s,int a, char *t,float sc,float w):Person(nam,s,a),Teacher(nam, s
29、,a, t),Student( nam, s,a, sc)wage=w; void show() cout“name: “nameendl;cout“age: “ageendl;cout“title: “titleendl;cout“sex: “sexendl;cout“score: “scoreendl;cout“wage: “wageendl; private:float wage; ;int main() Graduate grad(“Yang_Li“, m, 28, “教授“,92.5,5500);grad.show();return 0; ,例3.4-5 虚基类的使用。 #inclu
30、de class A public:int a;A(int x = 0) a = x; ; class B1 : virtual public A public:int b1;B1( int x = 0, int y = 0):A(x)b1 = y;void print()cout“B1:a=“a“,b1=“b1endl; ; class B2 : virtual public A public:int b2;B2( int x = 0, int y = 0):A(x)b2 = y;void print() cout“B2:a=“a“,b2=“b2endl; ;,class C : publi
31、c B1, public B2 public:int c;C(int x, int y, int m, int n,int s):B1(x,y), B2(m,n) c = s; void print() B1:print();B2:print();cout“c = “cendl; ; void main() C c1(100,200,300,400,500);c1.print(); c1.a=1000;c1.print(); ,第3讲 C+面向对象程序设计,3.4 继承与派生类,3.4.6 继承与组合,在一个类中,以另一个类的对象作为数据成员的,称为类的组合。,例如:,class Person
32、 public: char *name;int age;char sex; ; class Birthdate public:.private:int year;int month;int day; ;,class Professor:public Person public:.private: Birthdate birthday; ;,*Professor类通过继承从Person类得到了name,age, sex等数据成 员,通过组合,从Birthdate类得到了 year, month, day等数据成员。继承是一种“是”的关系,而组合是一种“有”的关系。 *,第3讲 C+面向对象程序设
33、计,3.4 继承与派生类,3.4.7 继承在软件开发中的重要意义,继承是面向对象技术的一个重要内容,也是C+和C的最重要的区别之一。对类库中的类声明一般是放在头文件中,类的实现是单独编译的。由于基类是单独编译的,在程序编译时,只需对派生类的新增功能进行编译,这就大大提高了程序调试的效率。如果在必要时修改了基类,只要基类的公共接口不变,派生类不必修改。为什么要求在软件开发中使用继承机制,尽量通过继承来建立一批新类?,(1) 许多基类是被程序的其他部分或其他程序使用的,这些程序 要求基类不能受破坏。,(2) 用户往往得不到基类的源代码。如果要修改已有的类,必须 掌握类的声明和类的实现。但是使用类库
34、,用户是无法知道成员函 数的代码的,因此无法对基类进行修改。,(3) 在类库中,一个基类可能已被指定与用户所需的组减建立了 某种关系,因此,在类库中基类是不容许修改的。,(4) 在类库中,许多类是专门作为基类而设计的。有些类可能没 有独立的功能,只是一个框架,或者说是一个抽象类,以便用户在 此基础上添加新的功能。,(5) 在面向对象的程序设计中,需要设计类的层次结构,从最初 的抽象类出发,每一层派生类的建立都逐步实现具体的目标。也可 以说,是不断地从抽象到具体的过程。,3.4.1 继承与派生的概述* 3.4.2 派生类成员的访问属性* 3.4.3 派生类的构造函数和析构函数* 3.4.4 多继承* 3.4.5 虚基类* 3.4.6 继承与组合* 3.4.7 在软件开发中的重要意义*,3.4 继承与派生类,小结:,