C应用与开发案例教程中实用.pptx





《C应用与开发案例教程中实用.pptx》由会员分享,可在线阅读,更多相关《C应用与开发案例教程中实用.pptx(253页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、6.1 概述 继承是C+语言的一种重要机制,该机制允许在既有类的基础上定义新的类,而不需要把既有类的内容重新书写一遍。继承是通过派生方式实现的。一个基类可以派生出多个派生类,这种从一个基类中的继承叫单继承。如果一个派生类由多个基类派生出来,称为多继承。派生类也可以作为基类再派生出新的类,形成类的层次结构。类有三种继承方式:公有继承(public)、私有继承(private)和保护继承(protected)。我们可以通过不同的继承方式限定成员的访问权限,以达到修改已有成员的目的。我们还可以通过同名覆盖、作用域限定符和虚基类的方法达到此目的。派生类继承了基类的所有成员,但构造函数和析构函数除外,因
2、此,在派生类中,想要进行特别的初始化和清理工作时,就要加入新的构造函数和析构函数。第1页/共253页6.1 概述 多态性是面向对象程序设计中的又一重要特征,多态的实现可分为编译时的多态和运行时的多态。编译时的多态,指程序在编译过程中确定函数操作的具体对象,通过函数重载来实现;运行时的多态,是指程序在运行过程中才能确定函数操作的具体对象,通过虚函数来实现。虚函数为我们提供了一种更为灵活的多态性机制,它体现的是运行时的多态,它允许函数调用与函数体之间的关系在运行时才建立。虚函数是用virtual关键字声明的非静态成员函数。当将基类的同名函数定义为虚函数时,我们就可利用基类类型的指针访问该指针指向的
3、派生类对象的同名原型函数,从而实现运行过程的多态。第2页/共253页6.2 派生类的概念6.2.1 基类和派生类 继承性在客观世界中是一种常见的现象。例如:当一个小孩出生时,就从父亲和母亲那里继承了一定的特征。随着时间的推移和环境的变化,这个小孩逐渐有了自己的性格特征,因此这个小孩就具备了从父母那里继承来的以及自己所独有的特征的组合。从面向对象程序设计的观点看,继承所表达的正是这样一种类与类之间的关系,这种关系允许在既有类的基础上创建新的类。在最简单的情况下,一个类B继承类A或者从类A派生出类B,通常类A称为基类(父类),类B称为派生类(子类)。这时,类B的对象具有类A对象的所有特性。也可以这
4、样说,类B从类A派生出来。这意味着类B至少描述了与类A同样的接口,至少包含了同类A一样的数据,可以共享类A的成员函数。第3页/共253页6.2 派生类的概念 类B继承了类A(或称类A派生了类B),那么类A的公有段成员可以传递给派生类B,当作类B自己的成员。在创建派生类对象时,先要调用基类的构造函数,以便分配基类的公有段成员存储空间;实际上,由于调用了构造函数,一个派生类对象包含有一个基类对象,只是对于派生类而言,不能访问基类的私有段成员。派生类的定义格式如下:class 派生类名:继承方式 基类名 /派生类成员定义 第4页/共253页6.2 派生类的概念 在上面的格式中,派生类名是新定义的一个
5、类名,它是从由“基类名”所标识的类派生而来的。这样定义的派生类继承了基类的除了构造函数和析够函数之外的所有成员,因此派生类对象由两部分组成:一部分是由基类继承的成员,另一部分是派生类新增加的自己特有的成员。“继承方式”用于规定派生类中从基类继承到的那部分成员在派生类中的访问控制权限。继承方式可用下列3个关键字之一来指定:public:公有继承;protected:保护继承;private:私有继承。第5页/共253页6.2 派生类的概念【例6-1】#include class A private:int pri;public:int pub;void set_pri(int a)pri=a;v
6、oid set_pub(int a)pub=a;void out_pri()coutpri”endl;class B:public A private:int pri1;public:int pub1;void set_pri1(int a)pri1=a;第6页/共253页6.2 派生类的概念 void set_pub1(int a)pub1=a;void out()coutpub”pri1”pub1endl;void main()A objA;objA.set_pri(1);objA.set_pub(2);objA.out_pri();B objB;objB.set_pri(3);objB.
7、set_pub(4);objB.set_pri1(5);objB.set_pub1(6);objB.out_pri();objB.out();第7页/共253页6.2 派生类的概念 程序的输出结果为:1 3 4 5 6 该程序创建了两个对象objA(A类对象)和objB(B类对象)。尽管B类没有包含像out_pri()这样的成员函数说明,对象objB仍可以调用基类的成员函数。使用了继承,B类的任何对象也是A类的对象。该程序创建了两个对象objA(A类对象)和objB(B类对象)。尽管B类没有包含out_pri()函数声明,但对象objB仍然可以调用out_pri(),因为B类继承了A类的公有成
8、员函数out_pri()。第8页/共253页6.2 派生类的概念6.2.2 继承方式 1公有继承 在上一小节中,我们用了公有继承的例子,这种类型的继承是最常用的。对于公有继承来说,基类的公有段成员和保护段成员在派生类中的访问属性不变。派生类的其他成员可以直接访问继承来的这些成员。而外部使用者只能通过对象来访问其公有成员。基类的私有成员是不可访问的(友员除外),就是说,无论是派生类的成员还是派生类的对象都无法访问基类的私有成员。应注意的是:基类的保护成员只能被派生类的成员访问,不能被派生类的对象访问。第9页/共253页6.2 派生类的概念【例6-2】#include class A protec
9、ted:int i,j;public:void get_ij();void show_ij();class B:public A int k;public:int get_k();void make_k();;class C:public B public:void f();;第10页/共253页6.2 派生类的概念 这里,类B由基类A公有派生而来,则A公有段和保护段的成员在B中也是公有段和保护段的成员。同时,B又公有派生出类C,这时,B的公有段和保护段的成员(包括从A继承过来的成员)在C中也是公有段和保护段的成员。下面是各成员函数的实现代码:第11页/共253页6.2 派生类的概念 void
10、 A:get_ij()coutij;void A:show_ij()couti”j”n”;int B:get_k()return k;void B:make_k()k=I+j;void C:f()i=5;j=6;第12页/共253页6.2 派生类的概念 可见,在B和C中都可以直接使用基类A的保护段中的成员i和j。下面的实现说明了怎样使用这些派生类。void main()B objB;C objC;objB.get_ij();objB.show_ij();objB.make_k();coutobjB.get_k()”n”;objC.f();objC.show_ij();第13页/共253页6.2
11、 派生类的概念 程序的输出结果为:Enter the two numbers:1 2 1 2 3 5 6 总之,一个派生类如果从基类公有派生出来,则基类成员的访问权限在派生类中保持不变。第14页/共253页6.2 派生类的概念 2.私有继承 当类的继承方式为私有继承时,基类公有段成员和保护段成员在派生类中作为私有成员,派生类的其他成员可以直接访问它们。但是,在外部通过派生类的对象无法访问。基类的私有成员仍然不可访问(友员除外),即不允许派生类的成员函数访问基类的私有成员。经过私有继承之后,所有基类的成员都成为派生类的私有成员,如果进一步派生的话,新的派生类的成员函数就不能访问已变成私有的基类的
12、成员。修改前面公有派生的例子如下:第15页/共253页6.2 派生类的概念【例6-3】#include class A protected:int i,j;public:void get_ij();void show_ij();class B:private A int k;public:int get_k();void make_k();class C:public B public:void f();第16页/共253页6.2 派生类的概念 这里,派生类B由基类A私有派生,A的公有段和保护段的成员在B中变成了私有段的成员。同时,C又由类B公有派生,则B的公有段和保护段的成员(注意:并不包括
13、从A继承过来的成员,它们属于B的私有段)成为C的公有段和保护段的成员。下面是各成员函数的实现:第17页/共253页6.2 派生类的概念void A:get_ij()coutij;void A:show_ij()couti”j”n”;int B:get_k()return k;void B:make_k()k=ij;void C:f()i=5;/错误 j=6;/错误 第18页/共253页6.2 派生类的概念 类A的保护段成员i和j已经成了类B的私有段成员,因此,B的派生类C以及B的对象都不能访问A的保护段成员i和j、以及A的公有段成员函数get_ij()和show_ij()。下面的实现说明了这些
14、派生类的使用。void main()B objB;C objC;objB.get_ij();/错误,外部对象无法访问私有成员 objB.show_ij();/错误,外部对象无法访问私有成员 objB.make_k();coutobjB.get_k()”n”;objC.show_ij();/错误,外部对象无法访问私有成员 第19页/共253页6.2 派生类的概念 3.保护继承 无论是公有继承,还是私有继承,派生类都不能直接访问基类的私有成员,要想访问某些私有成员只能通过调用基类的成员函数,这样显得很不方便。要想使用这些私有成员既便于派生类访问,又禁止外界对它的操作,可以把这些私有成员定义为保护成
15、员。当派生类使用保护继承方式派生时,基类的公有成员和保护成员在派生类中具有保护成员访问属性。这样,派生类的其他成员函数就可以直接访问它们,但在类外部通过派生类的对象无法访问。而基类的私有成员仍然是不可访问的(友员除外)。第20页/共253页6.2 派生类的概念 对于私有继承和保护继承的直接派生类中,基类私有成员都是不可见的,基类保护成员和公有成员是可见的;对派生类对象而言,所有成员都不可见。两种继承方式的效果似乎完全相同。但是,如果派生类作为新的基类,继续派生时,二者的区别就出现了。假设A类以私有继承方式派生B类,B类又派生C类,那么C类的成员函数和对象都不能访问间接从A类中继承来的成员。如果
16、A类以保护继承方式派生B类,那么A类中的公有和保护成员在B类中都是保护成员。B类再派生出C类后,A类中的公有和保护成员被C类继承后,有可能是保护的或者是私有的(由类C对类B的继承方式决定)。因此,C类的成员有可能可以访问间接从类A中继承来的成员。第21页/共253页6.2 派生类的概念【例6-4】#include class A int i;protected:int j;public:void get_ij();coutij;void show_ij();couti“”j”n”;class B:protected A int k;public:int get_k();return k;第22
17、页/共253页6.2 派生类的概念 void make_k();k=i+j;/错误,不能访问基类私有成员 ;class C:public B public:void f();i=5;/错误,不能访问基类私有成员 j=6;/正确,在派生类中是保护成员 ;第23页/共253页6.2 派生类的概念6.2.3 调整访问声明 基类成员被派生类继承后,在派生类中的访问声明主要由派生类定义时的继承方式来决定。但是,在C+程序设计过程中,我们希望基类某些成员的访问声明以私有或保护继承方式时,在派生类中的访问声明不变,保持在基类中的访问声明,这可通过调整访问声明来实现。格式如下:基类类名:基类保护段或公有段数据
18、成员 基类类名:基类保护段或公有段成员函数名第24页/共253页6.2 派生类的概念例如:class A int a;public:int b,c;int af();class D:private A int d;public:A:c;/调整对A:c的访问声明 int e;int df();第25页/共253页6.2 派生类的概念 类D从基类A私有派生,类A的所有公有段和保护段的成员都为类D的私有段,使用访问声明 A:c 可以将类B的公有段成员c在私有派生类D中显式声明为公有的,D的派生类可以访问它。由此可见,调整访问声明是私有派生的一种补充。对访问声明的调整要注意以下几点:第26页/共253
19、页6.2 派生类的概念1调整时不能说明任何类型。class A int a;public:int b,c;int af();class D:private A int d;public:int A:c;/错误 ;第27页/共253页6.2 派生类的概念 2.对访问声明的调整仅用于派生类中恢复名字的访问权限,不允许在派生类中降低或提升基类成员的可访问性。即:基类中的公有段成员或保护段成员在派生类中仅能说明为相对应的公有段成员或保护段成员;基类的私有成员不能用于访问声明的调整。从类的封装性的角度来看,这一限制是可以理解的。因为如果派生类能将其基类的私有成员用访问声明提高其访问权限而成为公有段的成员
20、,这就破坏了类的封装性。第28页/共253页6.2 派生类的概念 class A int a;protected:int b;public:int c;class D:private A protected:A:b;A:c /错误,不能降低基类成员的可访问性 public:A:c;A:a;/私有成员不能用于访问声明的调整 ;第29页/共253页6.2 派生类的概念 3对重载函数名的访问声明将调整基类中具有该名的所有函数的访问权限。由于调整访问声明仅仅是恢复名字的访问,对于重载函数名,它的访问声明将使所有同名的重载函数的访问权限都得到调整。class A public:f();f(int);cl
21、ass B:private A public:A:f;/使A:f()和A:f(int)在B中都是公有的 ;第30页/共253页6.2 派生类的概念 其中,A:f()表示访问声明仅仅调整名字,该函数名不带任何参数和类型;同时,它使得A:f()和A:f(int)在类B中都处于公有段。class A private:f(int);public:f();class B:private A public:A:f;/错误,访问声明具有二义性,不能调整其访问 ;第31页/共253页6.2 派生类的概念 同时也意味着,如果派生类和基类有同名的成员,则不可调整基类成员的访问。class A public:voi
22、d f();class B:private A public:void f();A:f;/错误,f的二次声明,不能调整访问 ;第32页/共253页6.2 派生类的概念6.2.4 类层次中的访问规则 1在派生类中对基类成员的覆盖 C+允许派生类重新定义基类的成员。如果派生类定义了与基类同名的成员,称派生类的成员覆盖了基类的同名成员。如果要在派生类中使用基类的同名成员,可以显式地使用如下格式:类名:成员来调用基类的成员。第33页/共253页6.2 派生类的概念 引用被覆盖的基类同名成员时,应使用类名限定符加以限定。当派生类与基类有同名成员时,引用不同的派生类对象中的这些成员时,还需指明对象名。应当
23、注意的是,不管是公有派生还是私有派生都不影响派生类对基类的静态成员的访问,但访问静态成员时,必须用“类名:成员”显式地说明。例如:第34页/共253页6.2 派生类的概念class A public:static void sa();/静态成员 void fa();class B:private A ;/全私有派生class C:public B void fc()A:sa();/正确 fa();/错误 sa();/错误 ;第35页/共253页6.2 派生类的概念 2.基类和派生类的赋值兼容规则 对于基类对象和派生类对象,在公有派生条件下,C+语言允许派生类对象到基类对象的自动转换,这通常称为
24、赋值兼容规则。赋值兼容规则:当派生类从基类公有继承时,允许以下4种派生类对象到基类对象的自动转换。规则1:可以用派生类对象为基类对象赋值;规则2:可以用派生类对象初始化基类引用对象;规则3:可以把指向派生类对象指针赋给基类对象的指针;规则4:可以把派生类对象的地址赋给基类对象的指针。每个派生类对象包含有一个基类对象,因此,上述规则不难理解。第36页/共253页6.2 派生类的概念6.2.5 派生类的构造函数和析构函数 派生类继承了基类的所有成员,但基类中的构造函数和析构函数是不能被继承的。当我们想对派生类中新添加的成员进行初始化时,就必须按实际需要添加新的构造函数。如果要对从基类继承下来的成员
25、进行初始化,则还要由基类的构造函数完成。当需要传递参数给基类构造函数时,必须为派生类建立一个构造函数,并由它来传递基类的构造函数所需的参数。在C+中,派生类构造函数的声明为:派生类构造函数(参数总表):基类名(参数表),对 象成员1(对象成员参数表),对象成员n(对象成员参数表)第37页/共253页6.2 派生类的概念 若基类使用缺省的构造函数或不带参数的构造函数,则在派生类中定义构造函数时可省略该基类名。如果基类定义了带有参数的构造函数,则派生类就应该定义构造函数,以保证对调用基类构造函数的对象进行初始化。派生类构造函数的调用顺序是:1.先祖先(基类),调用基类的构造函数。2.再客人(对象成
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 应用 开发 案例 教程 实用

限制150内