c++包含与继承ppt课件.ppt
《c++包含与继承ppt课件.ppt》由会员分享,可在线阅读,更多相关《c++包含与继承ppt课件.ppt(83页珍藏版)》请在三一办公上搜索。
1、C+包含与继承,复用已有的类,Contents,7.1 包含复用类的实现,包含表示一个类含有一个基本数据元素或对象除了简单类型的数据成员之外,也可以将一个类的对象作为另一个类的成员包含语法有时也被称作“组合”,特指C+中的对象成员语法现象包含用来实现“has-a”关系,对象成员,包含已有类的对象作为成员,可以通过成员对象使用已有类的功能,复用其实现如果将嵌入的对象作为新类的公有成员,那么除了使用新类接口中提供的功能之外,还可以向其中包含的成员对象发送消息程序7.1 public对象成员更常用的方式是将嵌入对象作为新类的私有成员,这时它是新类内部实现的一部分。新类中的方法可以使用成员对象提供的功
2、能,但新类只向外部提供自己的接口,隐藏了包含的成员对象程序7.2 private对象成员,对象成员的初始化,在创建一个包含对象成员的组合对象时,会调用成员类的构造函数初始化对象成员成员对象的初始化使用初始化列表语法当组合对象被撤销时,会调用其析构函数,成员对象的析构函数也会被调用析构函数的调用次序和构造函数相反,class Member int x;public:Member(int iv):x(iv);class withMembersint y;Member m;public: withMembers(int a, int b):m(a),y(b);,对象成员的初始化,成员对象的初始化表如
3、果没有在初始化列表中对成员对象进行显式初始化,编译器会为成员对象调用缺省构造函数,如果成员对象所属的类不存在缺省构造函数,会引起编译错误类中如果包含多个对象成员,在初始化列表中将它们用逗号隔开成员初始化的次序和成员声明的次序相同,并不考虑它们在初始化列表中的排列顺序,class Member1 int x;public:Member1(int iv):x(iv);class Member2 int y;public:Member2(int iv):y(iv);class withMembersMember1 m1;Member2 m2;public: withMembers(int a) :
4、m2(a), m1(a) ;,包含的进一步讨论,包含和类的复用如果希望复用一个类的实现,或使用一个类的功能,使用包含是一种简单而有效的方法。在新类中封装一个已有类的对象,让它作为新类实现的一部分去完成相关的操作,实现新类的功能按值包含包含已有类的对象作为新类的成员按指针(或引用)包含包含成员类对象的指针或引用作为新类的成员,包含的进一步讨论,组合在UML中,将“整体部分”关系称为“组合(composition)”组合关系的特点是成员对象是组合对象的一部分,随着组合对象的创建而创建,随着组合对象的撤销而撤销,成员对象并不作为独立元素对外部展现按值包含用来实现“整体部分”关系,包含的进一步讨论,聚
5、合聚合也描述组成关系,但是比组合更松散聚合关系的特点是成员对象可以独立于聚合对象而存在。当聚合对象被创建或撤销时,其成员对象可以不受影响,而只是它们之间的关系受到影响聚合通常使用按指针(或引用)包含的语法实现,包含的进一步讨论,组合与聚合示例,class MailBody;class Attachmentstring filename;/其他成员;,class Emailstring title;MailBody body;vector attch;public:void edit()void save()void send(string receiverAddr)void addAttch(
6、Attachment* a)attch.push_back(a); ;,包含的进一步讨论,关联关系除了组合与聚合之外,现实中的对象之间还存在着很多更广泛的关系UML中的关联(association)关系关联在C+中用按指针包含的语法实现,class BankAccount/银行账户类long accountNo;double balance;string clientName;public:BankAccount(long aNo, string name, double bal);class Client/客户类string name;string address;BankAccount*
7、acc;/ BankAccount* accounts5; / vector accounts/public:Client(string nm, BankAccount* a):name(nm) acc = a;/一种可能的银行开户操作如下:BankAccount ba(18024, Xavi, 5000);Client Xavi(Xavi, ,7.2 继承复用类的接口,泛化和继承现实中的概念之间还存在另一类常见关系,描述概念的层次或分类如生物系统中的门、纲、目、科、属、种等在UML中用泛化描述这类关系,在C+中则用继承语法实现继承是面向对象的核心特征之一,也是一种复用已有类的机制。在已有类的
8、基础上继承得到新类型,这个新类型自动拥有已有类的特性,并可以修改继承到的特性或者增加自己的新特性,继承的语法,class student /学生string name;int student_id;string department;public:student(string nm, int id, string dp);void print()const;,class grad_student /研究生string name;int student_id;string department;string thesis;public:grad_student(string nm, int id
9、, string dp, string th); void print()const;,继承的语法,研究生类定义中存在的问题在grad_student类中包含了student类的所有成员,两个类的代码有部分重复现实中,研究生也是学生,但是上面的类定义并没有体现出这种关系。应该将grad_student是student的事实更明确地表达出来这样的“is-a”关系用继承实现,class grad_student : public student string thesis;public:grad_student(string nm, int id, string dp, string th);vo
10、id print()const;,继承的语法,继承的语法形式class 派生类名字 : 访问限定符 基类名字成员声明;如果不指定访问限定符,则默认为private相关术语在C+中,被继承的已有类称为基类,继承得到的新类称为派生类派生类可以再被继承,这样构成的层次结构称为继承层次派生类继承了基类的数据成员和成员函数,只需要对自己不同于基类的行为或自己扩展的行为编写代码,基类成员在派生类中的可见性,基类成员在派生类中的可见性由两个因素决定:成员在基类中的访问限定和继承时使用的访问限定符基类成员的访问限定public成员在任何类和函数中都是可以访问的private成员只有本类或本类的友元可以访问,在
11、其他类和函数中不可访问,在自己的派生类中也同样不可访问protected成员的访问权限介于public和private之间:对它的派生类来说,protected成员和public成员一样是可访问的,但对其他类和函数而言,protected成员就如同private成员一样不可访问,基类成员在派生类中的可见性,ublic公有继承基类的public成员和protected成员分别作为派生类的public成员和protected成员被继承基类的private成员被继承,但在派生类中不可见,基类成员在派生类中的可见性,rivate私有继承基类的public成员和protected成员被派生类作为自己的p
12、rivate成员继承下来基类的private成员被继承,但在派生类中不可见,基类成员在派生类中的可见性,rotected保护继承基类的public成员和protected成员都被派生类作为自己的protected成员继承下来基类的private成员被继承,但在派生类中不可见,基类成员在派生类中的可见性,基类成员在派生类中的可见性,class Basepublic:int m1;protected:int m2;private:int m3;class D1 : public Base / D1中的成员和访问权限如何?;class D2 : private Base / D2中的成员和访问权限如
13、何?;class D3 : protected Base / D3中的成员和访问权限如何?;,基类成员在派生类中的可见性,继承和封装性通过继承基类,派生类就拥有了访问基类protected成员的特权。如果担心基类的封装性会因此被破坏,可以将基类中的所有数据成员都声明为private,而不是protected如果派生类真的需要访问基类的属性,就在基类中为其提供相应的protected访问器函数,class Baseint attr;protected:int getAttr();void setAttr(int);,访问声明,如果要在派生类中对继承的基类成员的可见性进行调整,可以使用访问声明,语
14、法形式为:class Derived : ( public | private | protected ) Basepublic ( | private | protected ):Base:成员名;/;访问声明的作用是在派生类中调整个别基类成员的访问限制,但是不能改变基类private成员的访问限制程序7.3 基类成员访问声明,公有继承和私有继承,公有继承和公有派生类公有派生类继承了基类的接口,能够发送给基类对象的消息派生类对象也可以接收可以将公有派生类看作是基类的子类型,即“is-a(是)”关系。公有派生类的对象也是基类的实例,但反之不成立私有继承和私有派生类私有派生类虽然继承了基类的所有
15、数据和功能,但这些只是作为派生类的部分私有实现,派生类的用户不能访问这些内部功能。基类和私有派生类之间不是类型和子类型的关系,私有派生类的对象也不能被看作是基类的实例,公有继承和私有继承,假定有Shape类的声明如下:class Shape public:void draw() const double area() const void move(int) ;如果想通过继承Shape类来创建一个新类型Line,应该使用public继承还是private继承呢?,公有继承和私有继承,公有继承如果Line要复用Shape类的接口,则使用public继承。公有派生类Line会被看作是一种特殊的Sh
16、ape,是Shape的子类型。Line类型的对象也是Shape类型的。Shape类中的area()操作显然不适合Line类型,可以通过私有化声明将其隐藏起来程序7.4 公有继承和私有化声明Line对象不能接收Shape对象可以接收的area()消息,Line和Shape不再具有相同的接口,Line严格说来已经不是一种Shape了,公有继承和私有继承,私有继承如果基类中只有个别操作适合新类,而大部分操作对派生类而言是不适合的,派生类不能使用基类的接口,甚至不能将派生类作为基类的子类型,这时可以使用私有继承私有继承时,基类的所有public成员在派生类中都变成了private。要让它们中的某些成员
17、可见,在派生类中进行public访问声明即可。程序7.5 私有继承和公有化声明采用了私有继承,所以Line不具备Shape的接口,也不被看作是Shape的子类型,它们之间不满足“is-a”关系,公有继承和私有继承,私有继承与复用类选择私有继承的一个主要原因是希望隐藏基类的接口私有继承方式使得从基类继承而来的成员隐藏在派生类内部,派生类没有继承基类的接口,派生类对象因而不能被看作是基类的实例,它们之间不满足is-a关系私有继承不再是类接口的复用,而是类实现的复用为了不滥用继承,同时考虑到包含的简单性,在这种情况下,通常会优先使用包含而不是私有继承。protected继承不常用,有时在一些多重继承
18、的应用实例中可以见到protected继承的使用,派生类对象的创建和撤销,派生类对象的结构平面坐标点类三维坐标点类Point3d对象的布局是怎样的?,class Point2dpublic:/对平面坐标点的操作protected:double _x, _y;,class Point3d : public Point2dpublic:/对三维坐标点的操作protected: double _z;,派生类对象的创建和撤销,派生类对象的结构派生类对象由其基类子对象以及派生类自己的非静态数据成员构成在派生类对象中,从基类继承而来的所有成员形成了一个基类子对象,就像是派生类对象的一个无名成员一样在派生类
19、对象的内存中,首先存储基类子对象,接下来存放派生类自己的其他数据成员因此,在派生类中,使用基类的非私有成员就像是使用派生类自己的成员一样,派生类对象的创建和撤销,派生类对象的结构和布局程序7.6 在派生类中使用基类的成员,派生类对象的创建和撤销,派生类对象的创建派生类对象中包含一个基类的子对象,那么在创建派生类对象时,也要初始化这个基类子对象,需要调用基类的构造函数。构造函数调用的次序是先调用基类构造函数,再调用派生类的构造函数。基类构造函数的调用可以是显式的,在派生类构造函数的初始化列表中指出基类构造函数及其实参如果在派生类的构造函数中没有显式调用基类构造函数,编译器会自动调用基类的缺省构造
20、函数来初始化派生类对象中的基类子对象;如果基类不存在缺省构造函数,编译器会报告错误,派生类对象的创建和撤销,包含其他成员对象的派生类对象如果一个派生类中还包含其他类的对象成员,则构造函数的调用次序是:先基类构造函数,再成员类的构造函数,最后调用派生类的构造函数派生类对象的撤销在撤销一个派生类对象时,基类子对象也被撤销。析构函数的调用次序和构造函数的调用次序相反,即,先调用派生类的析构函数,再调用基类的析构函数程序7.7 构造函数和析构函数的调用,派生类对基类的修改,派生类不等同于基类继承使基类的代码进入派生类中,公有派生类便自动拥有了基类的行为和接口如果在派生类中不对这些行为或接口做任何修改,
21、派生类将无法区别于基类,这在实际编程中毫无意义派生类在继承基类的基础上,应该体现与基类的不同在派生类中修改基类的方式有两种:覆盖或隐藏基类的操作:重新定义基类接口中已经存在的操作,从而改变继承到的行为,使得派生类对象在接收到同样的消息时其行为不同于基类对象扩充接口:向派生类的接口中添加新操作,使得派生类对象能够接收更多的消息,覆盖和隐藏,覆盖与同名隐藏如果派生类没有重新定义基类接口中的操作,那么当派生类对象接收到相应的消息时会调用基类操作进行处理程序7.8 Point3d类继承得到Point2d类的成员派生类继承的某些基类操作如果不能满足派生类的需要,就要在派生类中重新定义基类的成员函数在派生
22、类中重新定义基类中的同名成员之后,原来基类中的名字在派生类中被隐藏程序7.9覆盖和名字隐藏,覆盖和隐藏,派生类重新定义基类操作的方式一覆盖在派生类中重定义基类接口中的成员函数,参数表和返回类型保持与基类中一致,这种情况称为覆盖(override)覆盖使派生类与基类的接口保持一致,但是基类的成员函数在派生类中被重定义,因而使派生类对象可以和基类对象接收相同的消息,却表现出不同于基类对象的行为派生类中如果覆盖了基类的同名函数,但是设置了不同的访问限制,也会引起派生类和基类接口的差异,覆盖和隐藏,派生类重新定义基类操作的方式二隐藏在派生类中重定义基类接口中的成员函数,并改变了函数的参数表或返回类型,
23、这种情况称为隐藏(name hiding),在派生类中定义的新版本将自动隐藏基类中的函数版本。隐藏和覆盖的效果不同,因为参数表或返回类型的改变,使得派生类的接口和基类接口已经不再一致,基类对象能够接收的消息,派生类对象将不能处理覆盖实际上是一种隐藏,只不过隐藏的是基类的实现,而保留了基类的接口,覆盖和隐藏,类作用域和名字隐藏C+中每个类都定义了一个类作用域派生类的作用域是包含在其基类作用域之内的作用域的同名隐藏原则:内层作用域中的名字将隐藏外围作用域中相同的名字作用域中名字的查找规则,如果在内层作用域中找不到某个名字,就会继续在其外围作用域中查找;如果在内层作用域中找到了某个名字,就使用这个名
24、字,扩充接口,扩充接口是指为派生类增加更多的数据或操作,class student string name;int student_id;string department;public:student(string nm, int id, string dp);void print()const;class grad_student : public studentstring thesis;public:grad_student(string nm, int id, string dp, string th);void print()const;void research() const;
25、void writepaper() const; ;,扩充接口,is-a和is-like-a如果扩充了派生类的接口,那么派生类对象可以接收的消息就有别于基类对象了能够发送给基类对象的消息仍然可以发送给派生类对象,反之,可以发送给派生类对象的消息未必就能发送给基类对象这时,派生类与基类之间可以被描述为“is-like-a”关系,虽然派生类对象仍然可以替代基类对象,但是这种替代是不纯粹的,替代原则向上类型转换,替代原则继承最重要的特性之一是替代原则在任何需要基类对象(或地址)的地方,都可以由其公有派生类的对象(或地址)代替。替代原则有时也被称为赋值兼容规则向上类型转换在C+语言中,替代原则直接由编
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- c+ 包含 继承 ppt 课件

链接地址:https://www.31ppt.com/p-2002332.html