
C笔记(6-10).pdf
62页第六章继承和派生 6.1继承和派生的概念一、派生类的派生|是指从一个或多个以前定义的类产生新类的过程,原有的类称为基类,新产生的类称为派生类,派生类继承了基类所有的数据成员和成员函数.派生类使用两种基本的面向对象技术,一种称为性质约束,即对基类的性质进行限制;另一种称为性质扩展,即增加派生类的性质相对基类,派生类可以有以下变化:增加新的成员;重新定义已有的成员函数;改变基类成员的访问权限二、继承|类的继承多指派生类继承基类的数据成员和成员函数为自己的成员,继承常用来表示类属关系,而不是构成关系C+中有|两种继承方式:单 一 继 承 和 多 重 继 承 对于前者,派生类只能有一个基类;对于后者,派生类可以有多个基类静态成员可以被继承,这时基类对象和派生类的对象共享该静态成员6.2单一继承一、单一继承的一般声明形式class 派生类名:访问控 制 基 类 名(private:成员声明列表protected:成员声明列表public:成员声明列表);其中,访问控制是指如何控制基类成员在派生类中的访问属性,它是关键字private、protected和 public中的一个,声明中的其余部分和类的声明类似。
二、派生类的构造函数和析构函数1、定义派生类的造函数的一般定义形式派生类名:派 生 类 名(参 数 表 0):基 类 名(参 数 表)函数体冒 号 后“基 类 名(参数表)”称为成员初始化列表,参数表给出所调用的基类构造函数所需要的实参,实参的值可 来 自“参 数 表 0”,也可由表达式给出2、派生类|析构函数的一般定义形*派生类名:派 生 类 名().函数体构造函数和析构函数也都可在类体内直接定义为内联函数,这时的定义形式需把上述定义式中的“派生类名:”去掉例 1:使用默认内联函数实现单一继承#include using namespace std;class Pointprivate:i nt x,y;public:Point(int a,int b)x=a;y=b;cout 点void Showxy()coutx=x,y=y;Point()(cout 删除点);class Rectangle:public Point private:int H,W;public:Rectangle(int a,int b,int h,int w):Point(a,b)H=h;W=w;cout 矩形/构造函数初始化列表void Show()coutH=H,W=W”;Rectangle()cout删除矩形);v o i d m a i n()R e c t a n g l e r l (3,4,5,6);生成派生类对象r l,r l 先后调用基类和派生类的构造函数进行初始化r l.Showxy();派生对象调用基类的成员函数,r l.S h o w();|派生对象调用派生类的成员函数)程序运行结果:点 矩 形 x=3,y=4 H=5,W=6删 除 矩 形 删 除 点3、小结由上例可看出,胸造函数和析构函数是不被继承的,所以一个派生类只能调用它的直接基类的构造函数|,当定义派生类的一个对象时,首先调用基类的构造函数,对基类成员进行初始化,然后执行派生类的构造函数,如果某个基类仍是一个派生类,则这个过程递归进行。
当该对象消失时,析构函数的执行顺序和执行构造函数时的顺序正好相反三、类的保护成员类的保护成员是指在类声明中以关键字p r o t c e t e d 声明的成员,保护成员具有私有成员和公靛员的双重角色:对派生类的成员函数而言,它是公有成员,可直接访问;而对其他函数而言,它是私有成员,不能直接访问,只能通过基类的对象访问1这样就解决了使用公有方式产生的派生类的成员函数虽然可直接访问基类中定义的或从另一个基类继承来的公有成员,但不能访问基类的私有成员的问题例 2:演示使用p r o t e c t e d 成员的实例#i n c l u d e u si n g n a m e sp a c e st d;c l a ss P o i n t p r o t e c t e d:i n t x,y;p u b l i c:P o i n t (i n t a,i n t b)x=a;y=b;/P o i n t 类构造函数为内联函数void Show()coutx=x,y=yendl;);class Rectangle:public Point private:int H,W;public:Rectangle(int,int,int,int);/声明 Rectangle 类的构造函数void Show()coutx=x,y=y,H=H,W=Wendl;);Rectangle:Rectangle(int a,int b,int h,int w):Point(a,b)(H=h;W=w;/|派生类的内联构造函数定义形式:派 生 类 名(参 数 表 0):基 类 名(参 数 表)void main()Point a(3,4);/定 义 Point类对象a,并调用Point类构造函数初始化Rectangle rl(3,4,5,6);定义 Rectangle 类对象 r l,并初始化a.Show();基类对象a 调用基类Show函数,输 出“x=3,y=4”rl.Show();派生类对象rl调用派生类Show函数,输 出“x=3,y=4,H=5,W=6”)说明:程序演示了:通过定义x、y 为基类保护数据成员,从而使派生类的成员函数Show能直接 访 问 x、y;如何在类体内声明函数原型,并在类体外进行定义。
在程序中,派生类虽然继承了基类的成员函数Show,但却对其进行了改造,使其能显示所有数据,这并不影响基类函数原来的功能为了以后还可以派生新类,可 将 H、W 也定义为保护成员,这样就可以放心的使用统一的Show函数了四、访问权限和赋值兼容规则1、公有派生和赋值兼容规则在公有派生情况下,可以通过定义派生类自己的成员函数来访问派生类对象继承来的公有和保护成员,但不能访问继承来的私有成员和不可访问成员(基类的基类的私有成员)所以当希望类的某些成员能够被派生类访问,而又不能被其他的外界函数访问的时候,就应当把它们定义为保护的,而千万不能把它们定义为私有的,否则在派生类中它们就会是不可访问的所谓|赋值兼容规则,就是在公有派生情况下,通过将基类的成员都定义为公有或保护的,从而使每一个派生类的对象都可作为基类的对象来使用的情况I比如,如果将基类的某个成员定义为私有的话,则派生类中继承的该成员就不能被派生类的成员函数访问,这样派生类的对象就不能作为基类的对象使用,也就不符合赋值兼容规则例 3:演示赋值兼容规则的实例#include using namespace std;class Point protected:int x,y;public:Point(int a,int b)x=a;y=b;/Point 类构造函数为内联函数void Show()coutnx=H x n,y=nyendl;);class Rectangle:public Point private:int H,W;public:Rectangle(int,int,int,int);声明 Rectangle 类的构造函数void Show()coutnx=H x n,y=Hyn,H=H S h o w();/指 针 p调用基类的成员函数S h o w,输 出“x=3,y=4”R e c t a n g l e*p b=&b;/定义派生类的指针p b,并用派生类对象b 的地址对其进行赋值p b-S h o w();/指 针 p b 调用派生类的成员函数,输 出“x=3,y=4,H=5,W=6”E K I /派生类对象的属性值更新基类对象的属性值a.S h o w();/输出更新后的保护成员数值“x=3,y=4”)2、公有继承“isa”和分层“has-a”的区别所 谓“i s a”,就是公有继承“就是一个”的含义,是指在公有继承的赋值兼容规则下,如果类B公有继承于类A,在可以使用类A的对象的任何地方,则 类 B的对象同样也能使用,即每一个类B的对 象“就是一个”类 A的对象,但反之则不然,即如果需要一个类B的对象,则 类 A的对象就不行。
所 谓“h a s-a”,就是分层时“有一个”的含义,分层也称包含、嵌入或聚合,它是一种处理过程,通过让分层的类里包含被分层的类的对象作为其数据成员,以便把一个类建立在另一些类之上例如一 个 p e r s o n 对象有一个名字、一个地址和两个号码,那 么 p e r s o n 类表示的就是一种h a s-a”的关系.3、公有继承存取权限表派生类一般都使用公有继承,对派生类而言,基类中的保护类型的成员介于私有和公有之间,派生类可以访问它,而类的对象、外部函数以及不属于本系类之外的类则不可访问它基类成员派生类成员函数基类和派生类对象外部函数P r i v a t e不可访问不可访问不可访问P r o t e c t e d可访问不可访问不可访问p u b l i c可访问可访问可访问4、私有派生私有派生时i,基类的私有和不可访问成员和公有派生时一样,在派生类中仍是不可访问的;而基类的公有和保护成员此时就成了派生类的私有成员,从而导致派生类的对象不能直接访问继承的基类成员,只能通过定义公有的成员函数作为接耳-更重要的是,虽然派生类的成员函数可通过自定义的函数访问基类的成员,但如果将该派生类作为基类再继续派生时,即使使用公有派生,原基类公有成员和保护成员在新的派生类中也将是不可访问的,只能通过调用派生类自定义的函数访问原基类的公有和保护成员,这样就切断了原基类与外界的联系。
私有派生的这种特点不利于进一步派生,因此实际中应用的不多例 4:私有派生的类继续派生的例子#include using namespace std;class Point private:int x,y;public:Point(int a,int b)x=a;y=b;/Point 类构造函数为内联函数void Show()cout,x=H x n,y=Hyendl;);class Rectangle:private Point 私有继承,其公有成员将成为派生类的私有成员private:int H,W;public:Rectangle(int a,int b,int h,int w):Point(a,b)H=h;W=w;void Show()Point:Show();coutH=H,W=Wendl;);class Test:public Rectangle /公有继承,仍能访问基类的公有成员public:Test(int a,int b,int h,int w):Rectangle(a,b,h,w)void Show()Rectangle:Show();void main()Point a(l,2);/定义基类对象a,并调用基类构造函数进行初始化Rectangle b(3,4,5,6);/定义派生类对象b,并调用构造函数初始化Test c(7,8,9,10);/定义再次派生类对象c,并调用构造函数初始化a.Show();输出“x=l,y=2b.Show();输出“x=3,y=4”“H=5,W=6”c.Show();/输出“x=7,y=8”“H=9,W=10”说明:上例中,基类Point的公有成员函数Show通过私有派生成了派生类Rectangle的私有成员函数,虽然派生类通过定义公有成员函数Rectangle:Show可以使用这时已是自己类私有成员的函数Point:Show,但再次派生的类Test虽是公有派生,却已无法使用基类的公有成员函数Show,即不能通过Point:Show();的方式使用Point类的Show函数,例中只能通过Rectangle:Show();的方式间接达到显示x、y的目的。
5、保护派生派生也可使用protected定义,这种。
