![]() ![]() |
|
计算机等级考试二级C++考点分析之继承和派生 | |
作者:佚名 文章来源:不详 点击数 更新时间:2008/4/18 14:40:35 文章录入:杜斌 责任编辑:杜斌 | |
|
|
考点1 继承和派生的基本概念 继承的实质就是建造新的派生类。派生类从一个或多个以前定义的基类继承数据和函数,同时增加或重新定义数据和操作。这就产生了类的层次性。换句话说,继承就是创建一个具有别的类属性和行为的新类的能力。我们把这种通过特殊化已有的类来建立新类的过程,叫做“类的派生”,原有的类叫做“基类”,新建立的类叫做“派生类”从类的成员角度来看,派生类自动地将基类的所有数据成员和除了构造,析构函数之外的全部成员函数作为自己的成员,这叫做“继承”。基类和派生类又可以分别叫做“父类”和“子类”。在C++中有两种继承:单继承和多继承。对于单继承,派生类中只能有一个基类;对于多继承,派生类可以有多个基类。单继承和多继承的基类和派生类的关 考点2 派生类的定义与构成 在C++中,定义派生类的一般形式为: 单继承的定义如下: class<派生类名>:<继承方式><基类名> { <派生类新定义的成员> }; 多继承的定义如下: class<派生类名>:<继承方式1><基类名1>, <继承方式2><基类名2>, … <继承方式n><基类名n> { <派生类新定义的成员> }; 其中,<继承方式>即派生类的访问控制方式,用于规定基类成员在派生类中的访问权限,即基类成员在派生类中是公有的、私有的或保护的。常用的3种继承方式是公有继承(public),私有继承(private)和保护继承(protected)。缺省的类继承方式是私有继承private . <派生类新定义的成员>是指定义的派生类自己的成员(除了从基类继承来的所有成员之外,新增加的数据成员和函数成员)。 派生类的成员由两部分构成:一部分是从基类继承得到的,一部分是自己定义的新成员,所有这些成员仍然分为公有(public),私有(private)和保护(protected)3种访问性质。 7.2 派生类对基类成员的访问 考点3 派生类对基类成员的访问 派生类继承了基类的全部数据成员和除了构造、析构函数之外的全部成员函数,但这些成员在派生类中的访问属性在派生过程中通过继承方式是可以调整的。通过公有继承(public),私有继承(private)和保护继承(protected)3种继承方式将具有公有(public),私有(private)和保护(protected)3种访问属性的基类成员在派生类中具有了新的访问属性。表7-l描述了派生类的继承访问属性。 从上表可以看出: (l)基类中的私有成员在派生类中是不可见的,只能在基类内部访问。 (2)派生类中的成员不能访问基类中的私有成员,但可以访问基类中的公有成员和保护成员。 (3) 在公有继承时,派生类的对象可以访问基类中的公有成员;派生类的成员函数可以访问基类中的公有成员和保护成员。 (4)在私有继承和保护继承时,基类的私有成员只能在基类内部访问,而无法再往下继承。 小提示: 在派生关系中,构造函数和析构函数是不能被继承的。 7.3 派生类的构造函数和析构函数 考点4 派生类的构造函数和析构函数 1.构造函数 由于构造函数不能被继承,因此,派生类的构造函数必须通过调用基类的构造函数来初始化基类成员所以,在定义派生类的构造函数时除了对自己的数据成员进行初始化外,还必须负责调用基类的构造函数使基类的数据成员得以初始化。如果派生类中还有其他类的对象成员时,还应包含对对象成员初始化的构造函数。派生类的构造函数的一般定义形式为: <派生类名>::<派生类名>(<总参数表>):<基类名1>(<参数表1>), … <基类名n>(<参数表n>), <成员对象名1><参数表n+1>,
… <成员对象名m>(<参数表n+m> { <派生类构造函数体> } 派生类构造函数的调用顺序如下: (1)基类的构造函数; (2)成员对象的构造函数(若存在); (3)为派生类的构造函数 若派生类中有多个基类,处于同一层次的各个基类的构造函数的调用顺序取决于定义派生类时声明的顺序(自左向右)。若派生类中有多个对象成员,这些对象成员构造函数的调用顺序取决于它们在派生类中的说明顺序。若这个基类仍是一个派生类,则这个过程递归进行。由于构造函数和析构函数是不能被继承的,所以,一个派生类只能调用它的直接基类的构造函数。 小提示: 对基类成员和新增成员对象的初始化必须在成员初始化列表中进行。 2.析构函数 当对象消失时,派生类的析构函数被执行。由于析构函数也不能被继承,因此在执行派生类的析构函数时,类的析构函数也将被调用。若有其他类的对象成员的话,还应执行对象成员的析构函数。析构函数的执行顺序是先执行派生类的析构函数,再执行对象成员所属类的析构函数,最后执行基类的析构函数,其顺序与执行构造函数时的顺序正好相反。 小提示: (1)若基类中有默认的构造函数或者根本没有定义构造函数时,则派生类构造函数的定义中可以省略对基类构造函数的调用。(2)在某些情况下,派生类构造函数的函数体可能为空,仅起到参数传递作用。 7.4 多继承与虚基类 考点5 多继承中的二义性问题 一般来说,对基类成员的访问必须是无二义性的,但是由于在多继承的情况下,可能造成对基类中某个成员的访问出现了不惟一的情况,则称为对基类成员访问的二义性问题。产生二义性问题的一种情况是从基类中派生其他类可能导致几个类使用同一个函数名或变量名;另一种情况是如果一个类从多个基类派生,而这些基类又有一个共同的基类,则在这个派生类中访间这个共同的基类中的成员时会产生二义性。 一般,解决二义性问题的方法有两种。 (1)通过作用域运算符(::)来解决二义性问题。 (2)在类中定义同名成员。 小提示: (1)由于二义性的原因,一个类不能从另一个类中直接一次以上。(2)二义性检查是访问权限检查之前进行的,因此,成员的访问权限是不能解决二义性问题的。 考点6 虚基类的定义 在多继承中,若在多条继承路径上,有公共基类,这个公共基类便会产生多个副本。为了解决二义性问题,把公共基类定义为虚基类。使用虚基类的继承称为虚拟继承。虚基类是对派生类而言的,所以,虚基类本身的定义同基类一样,在定义派生类时声明该基类为虚基类即可,就是冠以关键字virtual。虚基类在定义由基类直接派生的类时说明说明的形式为: class<派生类名>:Virtual<继承方式><基类名> 其中,一个派生类可以公有、私有或保护地继承一个或多个虚基类,关键字virtual和关键字public,private或protected的相对位置无关紧要,但要放在基类名之前,并且关键字virtual只对紧随其后的基类名起作用。 引入虚基类后,派生类(即子类)的对象中只存在一个虚基类的子对象。当一个类有虚基类时,编译系统将为该类的对象定义一个指针成员,让它指向虚基类的子对象。该指针称为虚基类指针。 小提示: 一个派生类的对象的地址可以直接赋给虚基类的指针。 考点7 虚基类的构造函数 虚基类的初始化是由虚基类的构造函数来实现的,需要注意的是,虚基类的构造函数必须只被调用一次。调用带有虚基类的派生类的构造函数的顺序应遵循以下规则。 (1)虚基类的构造函数在非虚基类之前调用。 (2)若同一层次中包含多个虚基类,这些虚基类的构造函数按它们说明的顺序调用。 (3)若虚基类由非虚基类派生而来,则仍然遵循先调用基类构造函数,再调用派生类中构造函数的执行顺序。 小提示: 在一般情况下,当定义虚基类的构造函数时,虚基类只允许定义不带参数的或带默认参数的构造函数。 7.5 虚函数与多态性 考点8 多态性与虚函数的概念 1.多态性 多态性也称后约束或动态约束,它常用虚函数来实现。在C++中,多态性是指C++的代码可以根据运行情况的不同而执行不同的操作。C++的多态性就是为同一个函数和运算符定义几个版本。C++支持两种多态性,编译时的多态性和运行时的多态性。编译时的多态性通过使用重载函数获得,运行时的多态性通过使用继承和虚函数来获得。在C++中,多态性的实现与函数联编有关,C++中有两种函数联编(绑定):静态联编和动态联编。静态联编是在程序编译时进行的;动态联编是在程序运行时进行的。 要获得多态性的对象,必须建立一个类等级,然后在派生类中重定义基类函数,该函数可以被定义为重载函数或函数或虚函数,以获得编译时的多态性对象或运行时的多态性对象。
2.虚函数 为实现某种功能而假设的函数称为虚函数虚函数是用关键字virtual进行说明虚函数是动态联编的甚础。虚函数只能是类中的一个成员函数,但不能是静态成员。说明虚函数的方法如下: virtual <类型说明符><函数名>(<参数表) 若某个类中的一个成员函数被说明为虚函数,这就意味着该成员函数在派生类中可能有不同的实现。当使用这个成员函数操作指针或引用标识对象时,对该成员函数调用采取动态联编方式,即在运行时进行关联或绑定。如果采用一般类型的标识对象来操作虚函数,则将采用静态联编方式调用虚函数。 考点9 纯虚函数和抽象类 1.纯虚函数 在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它说明为纯虚函数,它的实现留给该基类的派生类去做。纯虚函数是一种特殊的虚函数,它的一般定义形式如下: class<类名> { virtual<类型><函数名>(<参数表>)=0; … }; 2.抽象类 一个类可以说明多个纯虚函数,带有纯虚函数的类称为抽象类。抽象类的主要作用是将有关的子类组织在一个继承层次结构中,由它来为它们提供一个公共的根,相关的子类是从这个根派生出来的。抽象类至少含有一个虚函数,而且至少有一个虚函数是纯虚函数,以便将它与空的虚函数区分开来。 关于抽象类的使用有下面几点规定: (l)抽象类只能用作其他类的基类,不能建立抽象类实例。 (2)抽象类不能用作参数类型、函数返回类型或显示转换的类型。 (3)可以说明指向抽象类的指针和引用,此指针可以指向它的派生类,进而实现多态性。 小提示: 在成员函数内可以调用纯虚函数,但在构造函数或析构函数内调用一个纯虚函数将导致程序运行错误,因为没有为纯虚函数定义代码。 |
|
![]() ![]() |