用的最重要的手段它允许程序员在保持原有类特性的基.ppt
《用的最重要的手段它允许程序员在保持原有类特性的基.ppt》由会员分享,可在线阅读,更多相关《用的最重要的手段它允许程序员在保持原有类特性的基.ppt(105页珍藏版)》请在三一文库上搜索。
1、继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构。体现了由简单到复杂的认识过程。,第八章 继承与多态,多态性(polymorphism)多态性是考虑在不同层次的类中,以及在同一类中,同名的成员函数之间的关系问题。函数的重载,运算符的重载,属于编译时的多态性。以虚函数为基础的运行时的多态性是面向对象程序设计的标志性特征。 体现了类推和比喻的思想方法。,第八章 继承与多态,8.1 继承与派生的概念,8.4 虚基类 (选读),8.3 多重继承与派生类
2、成员标识,8. 6 多态性与虚函数,8.5 派生类应用讨论,8.2 派生类的构造函数与析构函数,8.1 继承与派生的概念,层次概念是计算机的重要概念。通过继承(inheritance)的机制可对类(class)分层,提供类型/子类型的关系。 C+通过类派生(class derivation)的机制来支持继承。被继承的类称为基类(base class)或超类(superclass),新产生的类为派生类(derived class)或子类(subclass)。 基类和派生类的集合称作类继承层次结构(hierarchy)。 如果基类和派生类共享相同的公有接口,则派生类被称作基类的子类型(subtyp
3、e)。 派生反映了事物之间的联系,事物的共性与个性之间的关系。 派生与独立设计若干相关的类,前者工作量少,重复的部分可以从基类继承来,不需要单独编程。,8.1 继承与派生的概念,8.1.1 类的派生与继承,8. 1.2 公有派生与私有派生,由基类派生出派生类的定义的一般形式为 class 派生类名:访问限定符 基类名1,访问限定符 基类名2,访问限定符 基类名n private: 成员表1; /派生类增加或替代的私有成员 public: 成员表2; /派生类增加或替代的公有成员 protected: 成员表3; /派生类增加或替代的保护成员 ;/分号不可少 其中基类1,基类2,是已声明的类。
4、在派生类定义的类体中给出的成员称为派生类成员,它们是新增加成员,它们给派生类添加了不同于基类的新的属性和功能。派生类成员也包括取代基类成员的更新成员。,8.1.1 类的派生与继承,(a)多重继承,(b)单继承,图8.1 多重继承与单继承,一个基类可以直接派生出多个派生类,派生类可以由多个基类共同派生出来,称多重继承。,8.1.1 类的派生与继承,如果一个派生类可以同时有多个基类,称为多重继承(multiple-inheritance),这时的派生类同时得到了多个已有类的特征。一个派生类只有一个直接基类的情况称为单一继承(single-inheritance)。,编制派生类时可分四步,吸收基类的
5、成员,改造基类成员,发展新成员,重写构造函数与析构函数,8.1.1 类的派生与继承,不论是数据成员,还是函数成员,除构造函数与析构函数外全盘接收,声明一个和某基类成员同名的新成员,派生类中的新成员就屏蔽了基类同名成员称为同名覆盖(override),派生类新成员必须与基类成员不同名,它的加入保证派生类在功能上有所发展。,8.1.1 类的派生与继承,上面的步骤就是继承与派生编程的规范化步骤。 第二步中,新成员如是成员函数,参数表也必须一样,否则是重载。 第三步中,独有的新成员才是继承与派生的核心特征。 第四步是重写构造函数与析构函数,派生类不继承这两种函数。不管原来的函数是否可用一律重写可免出错
6、。,访问控制,亦称为继承方式,是对基类成员进一步的限制。访问控制也是三种: 公有(public)方式,亦称公有继承 保护(protected)方式,亦称保护继承 私有(private)方式, 亦称私有继承。,8.1.2 公有派生与私有派生,访问限定符有两方面含义:派生类成员(新增成员)函数对基类(继承来的)成员的访问(调用和操作),和从派生类对象之外对派生类对象中的基类成员的访问。,公有派生是绝对主流。,派生类的构造函数的定义形式为: 派生类名:派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),基类名n(参数表n),成员对象名1(成员对象参数表1),成员对象名m(成员对象参数表
7、m) /派生类新增成员的初始化; /所列出的成员对象名全部为新增成员对象的名字,在构造函数的声明中,冒号及冒号以后部分必须略去。 所谓不能继承并不是不能利用,而是把基类的构造函数作为新的构造函数的一部分,或者讲调用基类的构造函数。基类名仅指直接基类,写了底层基类,编译器认为出错。 冒号后的基类名,成员对象名的次序可以随意,这里的次序与调用次序无关。,8.2 派生类的构造函数与析构函数,派生类构造函数各部分的执行次序为: 1.调用基类构造函数,按它们在派生类定义的先后顺序,对基类成员进行初始化。 2.调用成员对象的构造函数,按它们在类定义中声明的先后顺序,顺序调用。 3.执行派生类的构造函数。,
8、*在派生类构造函数中,只要基类不是使用缺省构造函数都要显式给出基类名和参数表。 如果基类没有定义构造函数,则派生类也可以不定义,全部采用系统给定的缺省构造函数。 如果基类定义了带有形参表的构造函数时,派生类就应当定义构造函数。,析构函数各部分执行次序与构造函数相反,首先对派生类新增一般成员析构,然后对新增对象成员析构,最后对基类成员析构。,【例8.1】由在册人员类公有派生学生类,【例8.1】由在册人员类公有派生学生类。我们希望基类和派生类共享相同的公有接口,只能采用公有派生来实现。,首先来看基类:,class Person string IdPerson; /身份证号,18位数字 string
9、 Name; /姓名 Tsex Sex; /性别enum Tsexmid,man,woman; int Birthday; /生日,格式1986年8月18日写作19860818 string HomeAddress; /家庭地址,public: Person(string, string,Tsex,int, string); /构造函数 Person(); /缺省的构造函数 Person(); /析构函数,【例8.1】由在册人员类公有派生学生类,void SetName(string); /修改名字 string GetName()return Name; /提取名字 void SetSex(
10、Tsex sex)Sex=sex; /修改性别 Tsex GetSex()return Sex; /提取性别 void SetId(string id)IdPerson=id; /修改身份证号 string GetId()return IdPerson; /提取身份证号 void SetBirth(int birthday)Birthday=birthday; /修改生日 int GetBirth()return Birthday; /提取生日 void SetHomeAdd(string ); /修改住址 string GetHomeAdd()return HomeAddress; /提取住
11、址 void PrintPersonInfo(); /输出个人信息 ;,接口函数:,【例8.1】由在册人员类公有派生学生类,派生的学生类:,class Student:public Person /定义派生的学生类 string NoStudent; /学号 course cs30; /30门课程与成绩 public: Student(string id, string name,Tsex sex,int birthday, string homeadd, string nostud); /注意派生类构造函数声明方式 Student(); /缺省派生类构造函数 Student(); /派生类析
12、构函数 SetCourse(string ,int); /课程设置 int GetCourse(string ); /查找成绩 void PrintStudentInfo(); /打印学生情况 ;,struct course char* coursename; int grade;,在VC+平台上运行例8.1,验证主函数,8.3 多重继承与派生类成员标识,由多个基类共同派生出新的派生类,这样的继承结构被称为多重继承或多继承(multiple-inheritance),图8.3 大学在册人员继承关系,8.3 多重继承与派生类成员标识,派生出来的新类同样可以作为基类再继续派生出更新的类,依此类推形
13、成一个层次结构。,例:输出派生类构造函数与析构函数的调用关系,#include class Base1 int x; public: Base1(int a) x=a; cout“调用基类1的构造函数!n“; Base1( ) cout“调用基类1的析构函数!n“; ; class Base2 int y; public: Base2(int a) y=a; cout“调用基类2的构造函数!n“; Base2() cout“调用基类2的析构函数!n“; ;,class Derived:public Base1, public Base2 int z; public: Derived(int a
14、, int b):Base1(a), Base2(20) z=b; cout“调用派生类的构造函数!n“; Derived() cout“调用派生类的析构函数!n“; ; void main(void) Derived c(100,200); ,例:派生类中包含对象成员,#inlucde “liti11-4.h” class Der:public Base1, public Base2 int z; Base1 b1, b2; public: Der(int a, int b):Base1(a), Base2(20), b1(200), b2(a+b) z=b; cout“调用派生类的构造函数
15、!n“; Der() cout“调用派生类的析构函数!n“; ; void main(void) Der d(100,200); ,本例中类Circle为圆;类Line为高;类Cone为圆锥,由Circle和Line公有派生而来。在Cone类中,Circle和Line类的接口完全不变,可以直接调用,这就是公有派生的优点。在Cone的成员函数中可直接访问Circle和Line中的公有成员,但不能直接访问私有成员。,【例8.2】由圆和高多重继承派生出圆锥,检证主程序:,圆类Circle定义,高类Line定义,圆锥类Cone定义,8.3.1 冲突 在多重派生时,若一个公有的派生类是由两个或多个基类派
16、生,当基类中成员的访问权限为public,且不同基类中的成员具有相同的名字时,出现了重名的情况。这时在派生类使用到基类中的同名成员时,出现了不唯一性,这种情况称为冲突。,class A public: int x; void Show()cout“x=“xn; A(int a)x=a; A() ; class B public: int x; void Show()cout“x=“xn; B(int a)x=a; B() ;,class C:public A, public B int y; public: void Setx(int a)x=a; void Sety(int b)y=b; i
17、nt Gety()return y; ; void main(void) C c1; c1.Show(); ,8.3 多重继承与派生类成员标识 (冲突、支配规则、赋值兼容规则),下面是编译时的出错提示: D:VCsourceL11_7.cpp(19) : error C2385: C:x is ambiguous(不明确的) D:VCsourceL11_7.cpp(19) : warning C4385: could be the x in base A of class C D:VCsourceL11_7.cpp(19) : warning C4385: or the x in base B
18、 of class C D:VCsourceL11_7.cpp(26) : error C2385: C:Show is ambiguous D:VCsourceL11_7.cpp(26) : warning C4385: could be the Show in base A of class C D:VCsourceL11_7.cpp(26) : warning C4385: or the Show in base B of class C 说明: 在派生类C中访问由基类继承来的变量x时,编译系统无法确定是要访问属于基类A中的x还是属于基类B中的x,因此编译出错。同样,在基类C的对象c1中
19、调用函数Show()时,也是无法确定是要调用类A中继承来的公有成员函数Show(),还是调用类B中继承来的公有成员函数Show()。,解决冲突问题的方法: 各基类中定义的成员函数名不同; 对于成员数据,在基类中说明其访问权限为private,并在相应的基类中提供成员函数对这些成员数据进行操作。 使用作用域分辨符来限定所访问成员的属性,其格式为: 类名:成员名;,class C : public A, public B int y; public: void SetAx(int a)A:x=a; /对类A中的x设置 void SetBx(int a)B:x=a; /对类B中的x设置 void S
20、ety(int b)y=b; int Gety()return y; ; void main(void) C c1; c1.SetAx(35); c1.SetBx(100); c1.Sety(300); c1.A:Show(); /调用类A中的成员函数 c1.B:Show(); /调用类B中的成员函数 cout“y=“c1.Gety()n; ,注意:当把派生类作为基类,又派生出新的派生类时,这种限定作用域的运算符不能嵌套使用,即:类名1:类名2: . :成员名; 也就是说,限定作用域的运算符只能直接限定其成员。,8.3.2 支配规则 在C+中,允许派生类中新增加的成员名与其基类的成员名相同,这
21、种相同不产生冲突。当没有使用作用域运算符时,则派生类中定义的成员名优先于基类中的成员名,这种优先关系称为支配规则。,class A public: int x; void Show()cout“x=“xn; ; class B public: int y; void Show()cout“y=“yn; ; class C:public A, public B public : int y; ;,void main(void) C c1; c1.x=100; c1.y=200; c1.B:y=300; c1.A:Show(); c1.B:Show(); cout“y=“c1.yn; cout“y
22、=“c1.B:yn; 运行结果为: X=100 Y=300 Y=200 Y=300,8.3.3 继承和对象成员,C+规定,任一基类在派生类中只能继承一次,否则会造成成员名的冲突。 Class A class B:public A, public A public: float x; . ; ; 此时在派生类B中包含了两个继承来的成员X,在使用时产生冲突。 解决的方法是,在类B的定义中加入类A的两个对象作为类B的成员(对象成员)。 Class B A a1, a2; ; 注意:在派生类中,如果权限允许的话可以直接使用基类的成员,但这里使用的是对象成员的成员,必须在对象名后加上成员运算符“.”和成
23、员名。,/例:基类成员与对象成员在使用上的差别 #include class A public: int x; A(int a=0)x=a; ; class B public: int y; B(int a=0)y=a; ; class C:public A int z; B b1; public: C(int a, int b, int m):A(a),b1(b) z=m; void show() cout“x=“xt;/直接使用成员名 cout“y=“b1.yt;/不能直接使用对象的成员名y cout“z=“zn; ;,void main(void) C c1(100,200,300);
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 最重要 手段 允许 程序员 保持 原有 特性
链接地址:https://www.31doc.com/p-3303233.html