全国计算机等级考试辅导讲义(C++部分)(7)

2019-08-26 17:29

佳恒计算机教育培训中心

(1)由于在类的声明中仅仅是对静态数据成员进行了引用性声明,因此必须在文件作用域的某个地方对静态数据成员进行定义并初始化,即应在类体外对静态数据成员进行初始化(静态数据成员的初始化与它的访问控制权限无关),而前面不加static,以免与一般静态变量或对象相混淆。初始化时不加该成员的访问权限控制符private,public等。 (2)静态数据成员初始化时前面不加static关键字,以免与一般静态变量或对象混淆。

(3)由于静态数据成员是类的成员,因此在初始化时必须使用作用域运算符(::)限定它所属的类。 2.静态成员函数

公有的静态数据成员可以直接访问,但私有的或保护的静态数据成员却必须通过公有的接口进行访问,一般将这个公有的接口定义为静态成员函数。使用static关键字声明的成员函数就是静态成员函数,静态成员函数也属于整个类而不属于类中的某个对象,它是该类的所有对象共享的成员函数。静态成员函数可以在类体内定义,也可以在类外定义。当在类外定义时,要注意不能使用static关键字作为前缀。由于静态成员函数在类中只有一个拷贝(副本),因此它访问对象的成员时要受到一些限制:

静态成员函数可以直接访问类中说明的静态成员,但不能直接访问类中说明的非静态成员;若要访问非静态成员时,必须通过参数传递的方式得到相应的对象,再通过对象来访问。 【考点七】 常成员

虽然数据隐藏保证了数据的安全性,但各种形式的数据共享却又不同程度地破坏了数据的安全性。因此,对于既需要共享又需要防止改变的数据应该定义为常量进行保护,以保证它在整个程序运行期间是不可改变的。这些常量需要使用const修饰符进行定义。

const关键字不仅可以修饰类对象本身,也可以修饰类对象的成员函数和数据成员,分别称为常对象、常成员函数和常数据成员。 1.常对象

使用const关键字修饰的对象称为常对象,它的定义格式如下:

<类名>const<对象名>或const<类名><对象名>常对象在定义时必须进行初始化,而且不能被更新。 2.常成员函数

使用const关键字说明的成员函数称为常成员函数,常成员函数的说明格式如下: <返回类型><成员函数名>(<参数表>)const; 3.常数据成员

使用const说明的数据成员称为常数据成员。常数据成员的定义与一般常量的定义方式相同,只是它的定义必须出现在类体中。常数据成员同样也必须进行初始化,并且不能被更新。但常数据成员的初始化只能通过构造函数的成员初始化列表进行。常数据成员的初始化只能在成员初始化列表中进行,但对于大多数数据成员而言,既可以使用成员初始化列表的方式,也可以使用赋值,即在构造函数体中使用赋值语句将表达式的值赋值给数据成员。这两种方式中,成员初始化列表方式使初始化情况更加明显,并且可能带来效率上的优势。 【考点八】 友元类

具有数据封装和隐藏的特性,只有类的成员函数才能访问类的私有成员,外部函数只能访问类的公有成员。但在某些情况下,需要在类的外部访问类的私有成员。这时,如果通过公有成员函数进行访问,由于参数传递、类型检查和安全性检查等需要时间上的开销,将影响程序的运行效率。为了解决整个问题,引入了友元。

友元可以在类外部直接访问类的私有成员,提高了程序的运行效率。友元提供了不同类或对象的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。

主讲教师:刘老师 咨询辅导答疑:QQ(30724125)

佳恒计算机教育培训中心

对于一个类,可以利用friend关键字将一般函数、其他类的成员函数或者是其他类声明为该类的友元,使得这个类中本来隐藏的信息(包括私有成员和保护成员)可以被友元所访问。如果友元是一般成员函数或是类的成员函数,称为友元函数;如果友元是一个类,则称为友元类,友元类的所有成员函数都成为友元函数。 1.友元函数

友元函数不是当前类的成员函数,而是独立于当前类的外部函数(包括普通函数和其他类的成员函数),但它可以访问该类的所有对象的成员,包括私有成员、保护成员和公有成员。友元函数要在类定义时声明,声明时要在其函数名前加上关键字friend。该声明可以放在公有部分,也可以放在私有部分。友元函数的定义既可以在类内部进行,也可以在类外部进行。 2.友元类

友元除了可以是函数外,还可以是类,即一个类可以作为另一个类的友元,称为友元类。友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。

友元类可以在另一个类的公有部分或私有部分进行说明,说明方法如下:friend<类名>;//友元类类名 【考点九】 对象数组

对象数组是指数组元素为对象的数组,该数组中的每一个元素都是同一个类的对象。对象数组的定义格式如下: <类名><数组名>[<大小>]??使用对象数组成员的一般格式是:<数组名>[<下标>].<成员名> 【考点十】 成员对象

类的数据成员可以是简单类型或自定义类型,也可以是类类型的对象。 因此,可以利用已定义的类来构成新的类,使得一些复杂的类可以由一些简单类组合而成。类的聚集,描述的就是一个类内嵌其他类的对象作为成员的情况。当一个类的成员是另外一个类的对象时,该对象就称为成员对象。 当类中出现了成员对象时,该类的构造函数要包含对成员对象的初始化,通常采用成员初始化列表的方法来初始化成员对象。定义的一般格式如下:

<类名>::<类名>(<总形参表>):<成员对象1>(<形参表1>),<成员对象2>(<形参表2<),?{//类成员的初始化}

建立一个类的对象时,要调用它的构造函数。如果这个类有成员对象,要首先执行所有的成员对象的构造函数,当全部成员对象的初始化都完成之后,再执行当前类的构造函数体。

析构函数的执行顺序与构造函数的执行顺序相反。当类中有多个成员对象时,要按照定义成员对象的顺序建立各个子对象,即成员对象构造函数的执行顺序仅与成员对象在类中声明的顺序有关,而与成员初始化列表中给出的成员对象的顺序无关。

如果在构造函数的成员初始化列表中没有给出对成员对象的初始化,则表示使用成员对象的缺省构造函数。如果成员对象所在的类没有缺省构造函数,将产生错误。如果所有的成员对象都是调用缺省构造函数建立的,那么该类的构造函数的成员初始化列表可以省略。

主讲教师:刘老师 咨询辅导答疑:QQ(30724125)

佳恒计算机教育培训中心

第7章 继承和派生

【考点一】 继承与派生 1. 基本概念

派生类从基类继承了各种成员的关系就称为继承。类的继承是新的类从已有类那里得到已有的特性。从已有的类产生新类的过程就是类的派生。在继承过程中,原有的类或已经存在的用来派生新类的类称为基类或父类,而由已经存在的类派生出的新类则称为派生类或子类。

从派生类的角度,根据它所拥有的基类数目不同,可以分为单继承和多继承。一个类只有一个直接基类时,称为单继承;而一个类同时有多个直接基类时,则称为多继承。从上面的描述可知,任何一个类都可以派生出一个新类,派生类也可以再派生出新类,因此,基类和派生类是相对而言的,一个基类可以是另一个基类的派生类,从而形成了复杂的继承结构,出现了类的层次。 基类与派生类之间的关系如下:

(1)基类是对派生类的抽象,派生类是对基类的具体化。基类抽取了它的派生类的公共特征,而派生类通过增加信息将抽象的基类变为某种有用的类型,派生类是基类定义的延续。 (2)派生类是基类的组合。多继承可以看作是多个单继承的简单组合。

(3)公有派生类的对象可以作为基类的对象处理。这一点与类聚集(成员对象)是不同的,在类聚集(成员对象)中,一个类的对象只能拥有作为其成员的其他类的对象,但不能作为其他类对象而使用。 2.派生类的定义与构成

定义派生类的一般格式如下:class<派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,??,<继承方式n><基类名n>{<派生类新定义成员>}; 其中,<基类名>是已有的类的名称,<派生类名>是继承原有类的特性而生成的新类的名称。

单继承时,只需定义一个基类;多继承时,需同时定义多个基类。<继承方式>即派生类的访问控制方式,用于控制基类中声明的成员在多大的范围内能被派生类的用户访问。每一个继承方式,只对紧随其后的基类进行限定。 继承方式包括3种:公有继承(public)、私有继承(private)和保护继承(protected)。如果不显式地给出继承方式,缺省的类继承方式是私有继承private。派生类新定义成员是指除了从基类继承来的所有成员之外,新增加的数据成员和成员函数。

在一个派生类中,其成员由两部分构成:一部分是从基类继承得到的,另一部分是自己定义的新成员,所有这些成员仍然分为公有(public)、私有(private)和保护(protected)三种访问属性。

其中,从基类继承下来的全部成员构成派生类的基类部分,这部分的私有成员是派生类不能直接访问的,公有成员和保护成员则是派生类可以直接访问的,但是它们在派生类中的访问属性将随着派生类对基类的继承方式而改变。 派生类继承了基类的全部数据成员和除了构造、析构函数之外的全部成员函数,但是这些成员在派生类中的访问属性在派生的过程中是可以调整的,继承方式控制了基类中具有不同访问属性的成员在派生类中的访问属性。

基类的成员有公有(public)、保护(protected)和私有(private)三种访问属性,类的继承方式也有公有继承(public)、保护继承(protected)和私有继承(private)三种。

不同的继承方式,导致具有不同访问属性的基类成员在派生类中具有了新的访问属性。 (1)基类中的私有成员在派生类中是隐藏的,只能在基类内部访问。

(2)派生类中的成员不能访问基类中的私有成员,可以访问基类中的公有成员和保护成员。此时派生类对基类中各成员的访问能力与继承方式无关,但继承方式将影响基类成员在派生类中的访问控制属性,基类中公有成员和保护成员在派生类中的访问控制属性将随着继承方式而改变:

主讲教师:刘老师 咨询辅导答疑:QQ(30724125)

佳恒计算机教育培训中心

派生类从基类公有继承时,基类的公有成员和保护成员在派生类中仍然是公有成员和保护成员;派生类从基类私有继承时,基类的公有成员和保护成员在派生类中都改变为私有成员 ;派生类从基类保护继承时,基类的公有成员在派生类中改变为保护成员,基类的保护成员在派生类中仍为保护成员。 【考点二】 派生类的构造函数和析构函数

1.派生类的数据成员由所有基类的数据成员与派生类新增的数据成员共同组成,如果派生类新增成员中包括其他类的对象(成员对象),派生类的数据成员中实际上还间接包括了这些对象的数据成员。因此,构造派生类的对象时,必须对基类数据成员、新增成员对象的数据成员和新增的其他数据成员进行初始化。 派生类的构造函数

必须要以合适的初值作为参数,隐含调用基类和新增成员对象的构造函数,用以初始化它们各自的数据成员,然后再对新增的其他数据成员进行初始化。 派生类构造函数的一般格式如下:

<派生类名>::<派生类名>(<总参数表>):<基类名1>(参数表1),?? <基类名n>(<参数表n>),

<成员对象名1>(<参数表n+1>),??,

<成员对象名m>(<参数表n+m>){<派生类构造函数体>} 派生类的构造函数名与类名相同。

在构造函数的参数表中,给出了初始化基类数据、成员对象数据以及新增的其他数据成员所需要的全部参数。在参数表之后,列出需要使用参数进行初始化的基类名和成员对象名以及各自的参数名,各项之间使用逗号分隔。 注意对基类成员和新增成员对象的初始化必须在成员初始化列表中进行。

当派生类有多个基类时,处于同一层次的各个基类的构造函数的调用顺序取决于定义派生类时声明的顺序(自左向右),而与在派生类构造函数的成员初始化列表中给出的顺序无关。如果派生类的基类也是一个派生类,则每个派生类只需负责它的直接基类的构造,依次上溯。 当派生类中有多个成员对象时,各个成员对象构造函数的调用顺序也取决于在派生类中定义的顺序(自上而下),而与在派生类构造函数的成员初始化列表中给出的顺序无关。 建立派生类对象时,构造函数的执行顺序如下:

(1)执行基类的构造函数,调用顺序按照各个基类被继承时声明的顺序(自左向右); (2)执行成员对象的构造函数,调用顺序按照各个成员对象在类中声明的顺序(自上而下); (3)执行派生类的构造函数。

派生类的构造函数只有在需要的时候才必须定义。派生类构造函数提供了将参数传递给基类构造函数的途径,以保证在基类进行初始化时能够获得必要的数据。因此,如果基类的构造函数定义了一个或多个参数时,派生类必须定义构造函数。如果基类中定义了缺省构造函数或根本没有定义任何一个构造函数(此时,由编译器自动生成缺省构造函数)时,在派生类构造函数的定义中可以省略对基类构造函数的调用,即省略\<基类名>(<参数表>)\。成员对象的情况与基类相同。当所有的基类和成员对象的构造函数都可以省略,并且也可以不在成员初始化列表中对其他数据成员进行初始化时,可以省略派生类构造函数的成员初始化列表。 派生类的析构函数

与构造函数相同,派生类的析构函数在执行过程中也要对基类和成员对象进行操作,但它的执行过程与构造函数严格相反,即:

(1)对派生类新增普通成员进行清理。

主讲教师:刘老师 咨询辅导答疑:QQ(30724125)

佳恒计算机教育培训中心

(2)调用成员对象析构函数,对派生类新增的成员对象进行清理。 (3)调用基类析构函数,对基类进行清理。

派生类析构函数的定义与基类无关,与没有继承关系的类中的析构函数的定义完全相同。它只负责对新增普通成员的清理工作,系统会自己调用基类及成员对象的析构函数进行相应的清理工作。 【考点四】 多继承与虚基类 1.多继承中的二义性问题

在派生类中对基类成员的访问应该是唯一的。但是,在多继承情况下,可能造成对基类中某个成员的访问出现了不唯一的情况,这时就称对基类成员的访问产生了二义性。要解决这一问题,有两种方法:

(1)通过作用域运算符(::)明确指出访问的是基类Basel的fun()函数,还是基类Base2的fun()函数。 使用作用域运算符进行限定的一般格式是: <对象名>.<基类名>::<成员名>//数据成员

<对象名>.<基类名>::<成员名>(参数表>) //成员函数 (2)在类中定义同名成员

对于在不同的作用域中声明的标识符的可见性原则是:如果存在两个或多个具有包含关系的作用域,外层声明的标识符如果在内层没有声明同名标识符,那么它在内层可见;如果内层声明了同名标识符,则外层标识符在内层不可见,这时称内层变量覆盖了外层同名变量。

在类的继承层次结构中,基类的成员和派生类新增的成员都具有类作用域,二者的作用范围不同,是相互包含的两个层,派生类在内层。这时,如果派生类定义了一个和某个基类成员同名的新成员(如果是成员函数,则参数表也要相同,参数不同的情况属于重载),派生的新成员就覆盖了外层同名成员,直接使用成员名只能访问到派生类的成员。 2. 虚基类的定义

当一个派生类从多个基类派生,而这些基类又有一个共同的基类,当对该基类中说明的成员进行访问时,可能出现二义性。虚基类就是为了解决这种二义性问题提出来的。在产生二义性问题的第二种情况中,产生二义性的最主要的原因是基类Base在派生类Derived2中产生了两个基类子对象,从而导致了对基类Base的成员data访问的不唯一性。要解决这个问题,只需使这个公共基类Base在派生类中只产生一个子对象即可。虚基类就可以完成这个任务。 虚基类的说明格式如下:

class<类名>:virtual<继承方式><基类名>

其中,关键字virtual与继承方式的位置无关,但必须位于虚基类名之前,且virtual只对紧随其后的基类名起作用。3. 虚基类的构造函数

使用虚基类解决二义性问题的关键是在派生类中只产生一个虚基类子对象。为初始化基类子对象,派生类的构造函数要调用基类的构造函数。对于虚基类,由于派生类的对象中只有一个虚基类子对象,所以,在建立派生类的一个对象时,为保证虚基类子对象只被初始化一次,这个虚基类构造函数必须只被调用一次。虽然继承结构的层次可能很深,但要建立的对象所属的类只是这个继承结构中间的某个类,因此将在建立对象时所指定的类称为最派生类。虚基类子对象由最派生类的构造函数通过调用虚基类的构造函数进行初始化。所以,最派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用;如果未列出,则表示使用该虚基类的缺省构造函数。由于最派生类总是相对的,因此,从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。 但只有用于建立对象的最派生类的构造函数才调用虚基类的构造函数,此时最派生类的所有基类中列出的对虚基类的构造函数的调用在执行过程中都被忽略,从而保证对虚基类子对象只初始化一次。

主讲教师:刘老师 咨询辅导答疑:QQ(30724125)


全国计算机等级考试辅导讲义(C++部分)(7).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:2010年国家公务员考试行测真题

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: