1、项目7 师生通讯录课件目录7.1 项目情景17.2 知识准备27.3 项目解决37.4 知识拓展47.1 项目情景 现实世界中的类不是孤立存在的,类与类之间有着一定的关系。设计师生通讯录管理系统,定义人类,在人类的基础上定义教师类与学生类,完成教师与学生信息的现实。我们即将面对的是面向对象的三大特点之一:继承。7.2 知识准备7.2.1 继承与派生 7.2.1 继承与派生1.基类与派生类(1)单继承基类基类人类的派生类人类的派生类研究生类的基类研究生类的基类7.2.1 继承与派生(2)多继承iostream的基类的基类iostream 的基类的基类istream与与ostream的派生类的派生
2、类7.2.1 继承与派生2.派生类定义单一继承派生类定义格式class 派生类名:继承方式 基类名 派生类新增加的数据成员 派生类新增加的成员函数;7.2.1 继承与派生例7.1 以人类为基类派生出学生类。class Person /定义基类private:string name;int age;char sex;public:Person(string n,int a,char s);void show_p();class Student:public Person/定义派生类private:派生类中新增加的数据成员int no;string bj;public:Student(string
3、 n,int a,char s,int n2,string b);派生类中新增加的成员函数void show_s();/;7.2.1 继承与派生说明1 在已有类的基础上派生出新类时在派生类中可以:(1)增加新的数据成员。(2)增加新的成员函数。(3)重新定义基类中已经有的函数。(4)改变现有成员的访问权限。(5)派生类成员包括基类成员和新增成员。说明2 继承方式有如下三种:(1)public (2)protected (3)private说明3 (1)构造函数不能够继承。(2)析构函数不能够继承。7.2.1 继承与派生思考:例7_1中Student类中有哪些数据成员和成员方法?7.2.1 继承
4、与派生3.继承方式 派生类继承了基类中除构造函数和析构函数之外的所有成员,但根据不同的继承方式其成员在派生类的访问权限也相应的发生了变化,其继承方式与成员访问权限变化规则如表所示。7.2.1 继承与派生 在基类中的访问权限在基类中的访问权限继承方式继承方式在派生类中访问权限在派生类中访问权限privatepublicpublicprivate(不可使用)protectedprotectedpublicpublicprivateprotectedprotectedprivate(不可使用)protectedprotectedpublicprotectedprivateprivateprivate
5、private(不可使用)protectedprivatepublicprivate7.2.1 继承与派生4.派生类构造函数派生类构造函数格式如下:派生类名(派生类构造函数总参数表):基类构造函数(参数表1),子对象名(参数2)派生类新增数据成员实始化7.2.1 继承与派生说明:(1)总参数表包括基类构造函数参数、子对象构造函数参数和派生类构造函数参数。(2)在定义派生类构造函数时参数表1和参数表2是参数名称列表。(3)派生类构造函数的调用顺序:调用基类构造函数。如果存在子对象,调用子对象类的构造函数。调用派生类构造函数。7.2.1 继承与派生例7.2 在例7.1派生类定义的基础上定义派生类S
6、tudent的构造函数。Student:Student(string n,int a,char s,int n2,string b):Person(n,a,s)no=n2;bj=b;7.2.1 继承与派生5.派生类析构函数析构函数和构造函数一样不能被继承,在派生类中定义析构函数与在一般类(无继承关系)中定义的方法相同。派生类中析构函数的调用顺序与构造函数相反。先调用派生类析构函数,如果存在子对象调用子对象类的析构函数,最后调用基类的析构函数。7.3 项目解决 使用面向对象的方法建立师生通讯录管理系统,该系统中存在的实体对象有学生和教师,他们具备一些共同的属性和方法。假设对于学生类命名为Stud
7、ent,教师类命名为Teacher。7.3 项目解决 1.由于Student与Teacher他们都具有姓名、性别等属性,都要完成对这些属性的显示,因此定义Person类做为他们的基类。class Personprivate:string name;int age;char sex;string tel;public:Person(string n,int a,char s,string t);void show_p();7.3 项目解决 2.在Person的基础上增加学生特有的(学号、班级)产生新类Student类,增加教师特有的(职工号、科室)产生新类Teacher类。(1)定义派生类Stu
8、dentclass Student:public Personprivate:int sno;/学号string bj;/班级public:Student(string n,int a,char s,string t,int sn,string b);void show_s();7.3 项目解决 (2)定义派生类Teacherclass Teacher:public Personprivate:int tno;/教职工号string office;/科室public:Teacher(string n,int a,char s,string t,int tn,string of);void sh
9、ow_t();7.3 项目解决 3.定义类的成员方法。Person:Person(string n,int a,char s,string t)name=n;age=a;sex=s;tel=t;7.3 项目解决 3.定义类的成员方法。void Person:show_p()cout姓名t年龄t性别t电话n;coutnametagetsexttelendl;/定义派生类Student的构造函数Student:Student(string n,int a,char s,string t,int sn,string b):Person(n,a,s,t)sno=sn;bj=b;7.3 项目解决 3.定
10、义类的成员方法。void Student:show_s()show_p();cout学号t班级n;coutsnotbjendlendl;/定义派生类Teacher的构造函数Teacher:Teacher(string n,int a,char s,string t,int tn,string of):Person(n,a,s,t)tno=tn;office=of;7.3 项目解决 3.定义类的成员方法。void Teacher:show_t()show_p();cout职工号t科室n;couttnotofficeendl2)个。(2)继承方式同单一继承,有三种:public、protected
11、、private。(3)构造函数、析构函数不能继承。7.4.1 多继承2.多继承派生类构造函数定义定义格式如下:派生类名(派生类构造函数总参数表):基类构造函数1(参数表1),基类构造函数2(参数表2),子对象名(参数3)派生类新增数据成员初始化说明:(1)此格式说明为2个基类,实际应用用可扩展到n(n2)个。(2)与单一继承的不同点是增加了“基类构造函数2(参数表2)”,用以完成对另外一个基类的初始化。7.4.1 多继承(3)构造函数的执行顺序 所有基类的构造函数,各基类构造函数的执行顺序由定义派生类时基类的顺序决定。如果存在子对象则执行子对象构造函数。执行派生类构造函数。7.4.1 多继承
12、例7.4 定义日期时间类由日期类与时间类派生,使用构造函数完成数据成员的初始化。定义基类日期基类 class Date private:int year;int month;int day;public:Date(int y,int m,int d);void showDate();7.4.1 多继承定义基类时间基类 class Timeint hour;int minute;int second;public:Time(int h,int m,int s);void showTime();7.4.1 多继承定义派生类日期时间类 class DateTime:public Date,publi
13、c Time /添加新的数据成员/添加新成员方法public:DateTime(int y,int m,int d,int h,int mi,int s):Date(y,m,d),Time(h,mi,s)void showDateTime();7.4.2 二义性二义性 在继承中一个派生类的成员包括了它的所有基类的成员(除构造函数与析构函数),在这个新成立的大家庭(派生类)中,存在同名成员的现象(比如两个人的名字都是Rose)是不奇怪的。当我们叫Rose时等待我们是两个Rose,这种访问的不唯一性和不确定性在C+中称为二义性。那么在家庭之中(派生类内)或在家庭之外(派生类外)我们如何区分他们,以
14、解决二义性呢?二义性归根结底是多继承中同名成员惹的祸。7.4.2 二义性二义性 1.基类中存在同名成员。class A protected:int Rose;public:A(int a)Rose=a;.;class B protected:int Rose;public:B(int a)Rose=a;.;7.4.2 二义性二义性class C:public A,public B/公有继承 A 和 B int y;public:void SetRose(int a)Rose=a;.;7.4.2 二义性二义性在基类A、B中存在同名成员Rose,在派生类C中访问Rose,不确定该Rose是A的还是
15、B的,就出现了二义性。解决此类二义性的方法是在成员的前面加上类名,用以唯一确定该成员。A:Rose 或 B:Rose7.4.2 二义性二义性2.基类与派生类出现同名成员。当基类和派生类出现同名成员时,默认情况下访问的是派生类中的成员。如果访问基类中成员可以通过加类名方式来访问。7.4.2 二义性二义性3.访问共同基类的成员时可能出现二义性。class A public:int Rose;public:A(int a)Rose=a;.;class B1:public A ;class B2:public A ;7.4.2 二义性二义性class C:public B1,public B2 int
16、 y;public:void SetRose(int a)Rose=a;.;B1由A继承Rose成员,B2由A也继承Rose 成员,在派生类C中访问Rose时,不确定是访问B1的Rose还是B2的Rose,出现了二义性。7.4.3 虚基类 7.4.3 虚基类引进虚基类的目的是为了解决二义性问题,使公共基类中的成员在其派生类中只产生一份基类成员。虚基类说明格式如下:virtual 7.4.3 虚基类例7.5 虚基类简单应用。class Apublic:int Rose;/共公基类中的Rose 7.4.3 虚基类class B1:virtual public A /A为B1的虚基类;class B
17、2:virtual public A /A为B2的虚基类;class C:public B1,public B2/C由B1,B2派生public:7.4.3 虚基类void SetRose(int a)Rose=a;/虚基类解决了Rose的二义性问题;7.4.4 多态多态面向对象的三大特点是封装、继承与多态。多态是生活中普遍存在的一种现象。在C+中多态是指同一段程序能够处理多种类型或对象的能力;指当不同的对象收到相同的消息时,产生不同的动作。C+的多态性具体体现在编译和运行两个方面,程序编译时多态性体现在函数和运算符的重载上,而在程序运行时的多态性通过继承和虚函数来体现。7.4.4 多态多态
18、7.4.4.1函数重载 在C+语言中,如果在声明函数原型时形式参数的个数或者对应位置的类型不同,两个或更多的函数就可以共用一个名字。这种在同一作用域中允许多个函数使用同一函数名的措施被称为重载(overloading)。函数重载是C+程序获得多态性的途径之一。1.函数重载的方法函数名字相同。函数名字相同。函数形式参数个数不同。函数形式参数个数不同。或或 函数的参数类型不同。函数的参数类型不同。7.4.4 多态多态例7.6 给出以下程序运行结果。int square(int x)return x*x;double square(double y)return y*y;void main()cou
19、tsquare(2)endl;coutsquare(1.5)endl;运行结果:运行结果:42.257.4.4 多态多态例7.7 实现求圆和矩形的周长。double length(float r)/用length()求圆的周长 return 2*PI*r;double length(float x,float y)/用Length()求矩形的周长 return 2*(x+y);void main()cout”圆周长:”length(r)endl;cout”矩形周长:”length(a,b)show_s();(3)一个指向基类的指针可用来指向从基类公有派生的任何对象,这一事实非常重要,它是C+实
20、现运行时多态的关键途径。7.4.4 多态多态7.4.4.4 虚函数 虚函数是在基类中冠以关键字 virtual 的成员函数。它提供了一种接口界面。虚函数可以在一个或多个派生类中被重定义。7.4.4.3 纯虚函数与抽象类 定义纯虚函数的一般格式为:class 类名 virtual 返回值类型 函数名(参数表)=0;7.4.4 多态多态 如果一个类中至少有一个纯虚函数,那么这个类被称为抽象类(abstract class)。抽象类中不仅包括纯虚函数,也可包括虚函数。抽象类中的纯虚函数可能是在抽象类中定义的,也可能是从它的抽象基类中继承下来且重定义的。抽象类有一个重要特点,即抽象类必须用作派生其他类的基类,而不能用于直接创建对象实例。抽象类不能直接创建对象的原因是其中有一个或多个函数没有定义,但仍可使用指向抽象类的指针支持运行时多态性。END