您好,欢迎访问三七文档
C++C++包含与继承复用已有的类Contents包含的语法和用途1继承的语法和用途2赋值兼容规则3包含与继承的选择47.1包含——复用类的实现包含表示一个类含有一个基本数据元素或对象除了简单类型的数据成员之外,也可以将一个类的对象作为另一个类的成员包含语法有时也被称作“组合”,特指C++中的对象成员语法现象包含用来实现“has-a”关系classStudent{stringname;longstuID;Datebirth;//…};classEgnine{……};classWheel{……};classCar{Enginee;Wheelwheels[4];…};对象成员包含已有类的对象作为成员,可以通过成员对象使用已有类的功能,复用其实现如果将嵌入的对象作为新类的公有成员,那么除了使用新类接口中提供的功能之外,还可以向其中包含的成员对象发送消息程序7.1public对象成员更常用的方式是将嵌入对象作为新类的私有成员,这时它是新类内部实现的一部分。新类中的方法可以使用成员对象提供的功能,但新类只向外部提供自己的接口,隐藏了包含的成员对象程序7.2private对象成员对象成员的初始化在创建一个包含对象成员的组合对象时,会调用成员类的构造函数初始化对象成员成员对象的初始化使用初始化列表语法当组合对象被撤销时,会调用其析构函数,成员对象的析构函数也会被调用析构函数的调用次序和构造函数相反classMember{intx;public:Member(intiv):x(iv){}};classwithMembers{inty;Memberm;public:withMembers(inta,intb):m(a),y(b){}};对象成员的初始化成员对象的初始化表如果没有在初始化列表中对成员对象进行显式初始化,编译器会为成员对象调用缺省构造函数,如果成员对象所属的类不存在缺省构造函数,会引起编译错误类中如果包含多个对象成员,在初始化列表中将它们用逗号隔开成员初始化的次序和成员声明的次序相同,并不考虑它们在初始化列表中的排列顺序classMember1{intx;public:Member1(intiv):x(iv){}};classMember2{inty;public:Member2(intiv):y(iv){}};classwithMembers{Member1m1;Member2m2;public:withMembers(inta):m2(a),m1(a){}};包含的进一步讨论包含和类的复用如果希望复用一个类的实现,或使用一个类的功能,使用包含是一种简单而有效的方法。在新类中封装一个已有类的对象,让它作为新类实现的一部分去完成相关的操作,实现新类的功能按值包含包含已有类的对象作为新类的成员按指针(或引用)包含包含成员类对象的指针或引用作为新类的成员包含的进一步讨论组合在UML中,将“整体-部分”关系称为“组合(composition)”组合关系的特点是成员对象是组合对象的一部分,随着组合对象的创建而创建,随着组合对象的撤销而撤销,成员对象并不作为独立元素对外部展现按值包含用来实现“整体-部分”关系包含的进一步讨论聚合聚合也描述组成关系,但是比组合更松散聚合关系的特点是成员对象可以独立于聚合对象而存在。当聚合对象被创建或撤销时,其成员对象可以不受影响,而只是它们之间的关系受到影响聚合通常使用按指针(或引用)包含的语法实现包含的进一步讨论组合与聚合示例classMailBody{…};classAttachment{stringfilename;//其他成员…};classEmail{stringtitle;MailBodybody;vectorAttachment*attch;public:voidedit(){…}voidsave(){…}voidsend(stringreceiverAddr){…}voidaddAttch(Attachment*a){attch.push_back(a);…}};包含的进一步讨论关联关系除了组合与聚合之外,现实中的对象之间还存在着很多更广泛的关系UML中的关联(association)关系关联在C++中用按指针包含的语法实现classBankAccount{//银行账户类longaccountNo;doublebalance;stringclientName;public:BankAccount(longaNo,stringname,doublebal){……}};classClient{//客户类stringname;stringaddress;BankAccount*acc;//BankAccount*accounts[5];//vectorBankAccount*accounts//…public:Client(stringnm,BankAccount*a):name(nm){acc=a;}};//一种可能的银行开户操作如下:BankAccountba(18024,Xavi,5000);ClientXavi(Xavi,&ba);7.2继承——复用类的接口泛化和继承现实中的概念之间还存在另一类常见关系,描述概念的层次或分类如生物系统中的门、纲、目、科、属、种等在UML中用泛化描述这类关系,在C++中则用继承语法实现继承是面向对象的核心特征之一,也是一种复用已有类的机制。在已有类的基础上继承得到新类型,这个新类型自动拥有已有类的特性,并可以修改继承到的特性或者增加自己的新特性继承的语法classstudent{//学生stringname;intstudent_id;stringdepartment;public:student(stringnm,intid,stringdp);voidprint()const;};classgrad_student{//研究生stringname;intstudent_id;stringdepartment;stringthesis;public:grad_student(stringnm,intid,stringdp,stringth);voidprint()const;};继承的语法研究生类定义中存在的问题在grad_student类中包含了student类的所有成员,两个类的代码有部分重复现实中,研究生也是学生,但是上面的类定义并没有体现出这种关系。应该将grad_student是student的事实更明确地表达出来这样的“is-a”关系用继承实现classgrad_student:publicstudent{stringthesis;public:grad_student(stringnm,intid,stringdp,stringth);voidprint()const;};继承的语法继承的语法形式class派生类名字:[访问限定符]基类名字{成员声明};如果不指定访问限定符,则默认为private相关术语在C++中,被继承的已有类称为基类,继承得到的新类称为派生类派生类可以再被继承,这样构成的层次结构称为继承层次派生类继承了基类的数据成员和成员函数,只需要对自己不同于基类的行为或自己扩展的行为编写代码基类成员在派生类中的可见性基类成员在派生类中的可见性由两个因素决定:成员在基类中的访问限定和继承时使用的访问限定符基类成员的访问限定public成员在任何类和函数中都是可以访问的private成员只有本类或本类的友元可以访问,在其他类和函数中不可访问,在自己的派生类中也同样不可访问protected成员的访问权限介于public和private之间:对它的派生类来说,protected成员和public成员一样是可访问的,但对其他类和函数而言,protected成员就如同private成员一样不可访问基类成员在派生类中的可见性public——公有继承基类的public成员和protected成员分别作为派生类的public成员和protected成员被继承基类的private成员被继承,但在派生类中不可见ABCABCinvisibleprivateprotectedpublicC公有继承B,B公有继承A基类成员在派生类中的可见性private——私有继承基类的public成员和protected成员被派生类作为自己的private成员继承下来基类的private成员被继承,但在派生类中不可见ABCABCinvisibleprivateprotectedpublicC私有继承B,B私有继承A基类成员在派生类中的可见性protected——保护继承基类的public成员和protected成员都被派生类作为自己的protected成员继承下来基类的private成员被继承,但在派生类中不可见ABCABCinvisibleprivateprotectedpublicC保护继承B,B保护继承A基类成员在派生类中的可见性protected不可见protectedprotectedprivate不可见privateprivateprotected不可见publicpublicprotectedprivatepublic基类成员限定符继承方式基类成员在派生类中的可见性classBase{public:intm1;protected:intm2;private:intm3;};classD1:publicBase{//D1中的成员和访问权限如何?};classD2:privateBase{//D2中的成员和访问权限如何?};classD3:protectedBase{//D3中的成员和访问权限如何?};基类成员在派生类中的可见性继承和封装性通过继承基类,派生类就拥有了访问基类protected成员的特权。如果担心基类的封装性会因此被破坏,可以将基类中的所有数据成员都声明为private,而不是protected如果派生类真的需要访问基类的属性,就在基类中为其提供相应的protected访问器函数classBase{intattr;protected:intgetAttr();voidsetAttr(int);};访问声明如果要在派生类中对继承的基类成员的可见性进行调整,可以使用访问声明,语法形式为:classDerived:(public|private|protected)Base{public(|private|protected):Base::成员名;//…};访问声明的作用是在派生类中调整个别基类成员的访问限制,但是不能改变基类private成员的访问限制程序7.3基类成员访问声明公有继承和私有继承公有继承和公有派生类公有派生类继承了基类的接口,能够发送给基类对象的消息派生类对象也可以接收可以将公有派生类看作是基类的子类型,即“is-a(是)”关系。公有派生类的对象也是基类的实例,但反之不成立私有继承和私有派生类私有派生类虽然继承了基类的所有数据和功能,但这些只是作为派生类的部分私有实现,派生类的用户不能访问这些内部功能。基类和私有派生类之间不是类型和子类型的关系,私有派生类的对象也不能被看作是基类的实例公有继承和私有继承假定有Shape类的声明如下:classShape{public:voiddraw()const{…}doublearea()const{…}voidmove(int){…}};如果想通过继承Shape类来创建一个新类型Line,应该使用public继承还是private继承呢?公有继承和私有继承公有继承如果Line要复用Shape类的接口,则使用public继承。公有派生类Line会被看作是一种特殊的Shape,是Shape的子类型。Line类型的对象也是Shape类型的。Shape类中的area()操作显然不适合Line类型,可以通过私有
本文标题:c++包含与继承
链接地址:https://www.777doc.com/doc-3591325 .html