1、第8章 继承、虚函数与多态性【本章学习要点】1.掌握单继承的定义、继承方式与访问控制;2.了解多继承的定义和应用;3.掌握虚函数的定义和作用;4.了解多态性。第8章 继承、虚函数与多态性8.1 单继承 8.2 多继承 8.3 虚函数 8.4 多态性 继承是面向对象程序设计的基本特征之一,是从已有的类基础上建立新类。继承性是面向对象程序设计支持代码重用的重要机制。面向对象程序设计的继承机制提供了无限重复利用程序资源的一种途径。8.1 单继承 继承是类之间定义的一种重要关系。定义类B时,自动得到类A的操作和数据属性,使得程序员只需定义类A中没有的新成分就可完成在类B的定义,这样称类B继承了类A,类
2、A派生了类B,A是基类(父类),B是派生类(子类)。这种机制称为继承。8.1 单继承8.1.1 派生类的定义派生类定义的一般形式如下:class :成员;有三种,分别是公有继承(public)、保护继承(protected)和私有继承(private),如定义时没有指明,则默认为私有继承(private)。8.1 单继承8.1.2 访问控制 类成员的访问控制分为公有、保护和私有三种。公有成员可以通过类的对象或类域范围内的成员函数来访问,而保护和私有成员只能由类域范围内的成员函数访问。8.1 单继承派生类中的成员既包括自身定义的,也包括从基类继承得到的。前者的访问控制和一般类中成员的访问控制一样
3、,对于后者(即从基类继承得到的成员)的访问控制,我们须搞清楚两个方面:8.1 单继承(续)1.派生类的成员函数对基类成员的访问控制。(1)派生类的成员函数可以直接访问基类的公有和保护成员。(2)派生类的成员函数不能访问基类的私有成员。8.1 单继承2.派生类的对象对基类成员的访问控制。类成员的访问控制不是用来限制类本身的成员函数对其数据成员的访问的,而是用来限制在类域之外的程序通过类的对象来访问类的成员的。基类成员在派生类中的访问控制是由其在基类中访问控制和继承方式共同决定的,具体情况见下表:8.1 单继承表8.1 继承方式对派生类中基类访问控制的影响 8.1 单继承(1)公有继承(publi
4、c)公有继承时,基类成员在派生类的访问控制保存不变,派生类的对象可以访问基类中的公有成员,派生类的成员函数可以访问基类中的公有成员和保护成员,不能访问基类中的私有成员。这里一定要区分清楚,派生类的对象和派生类中的成员函数对基类成员的访问是不同的。8.1 单继承(2)保护继承(protected)保护继承时,基类中公有成员和保护成员都成为派生类的保护成员,只能被它的派生类成员函数访问,基类的私有成员仍然是私有的,不能被派生类的成员函数和其对象访问。8.1 单继承(3)私有继承(private)在私有继承时,基类的成员只能由直接派生类访问,而无法再往下继承。也就是说基类中公有成员和保护成员作为派生
5、类的私有成员时,不能被这个派生类的子类访问。8.1 单继承8.1.3 域运算符:如果派生类定义了与基类同名的成员,若要在派生类中使用基类同名成员,可以用域运算符加以指定。使用格式如下:类名:成员 8.1 单继承8.1.4 构造函数与析构函数的执行顺序 当一个类是派生类,而且有对象成员时,它的构造函数的执行顺序是这样的:先调用基类的构造函数,再调用对象成员的构造函数,最后才调用这个类自己的构造函数。这样的顺序能够保证对象正确地构造。8.1 单继承而对象结束生存期时,要调用析构函数来释放对象的资源,这时析构函数的调用顺序正好与构造函数相反:先调用派生类的析构函数,再调用对象成员的析构函数,最后才调
6、用基类的析构函数。这样的顺序也是为了保证对象能够正确地被释放。8.1 单继承8.1.5 基类与派生类的关系1.派生类是基类的具体化。2.派生类是基类定义的延续。3.派生类是基类的组合。8.2 多继承8.2.1 多继承的定义 当一个类从多个类派生而来时,就称为多继承。多继承时派生类定义的形式如下:class :【,】成员;8.2 多继承8.2.1 多继承的定义 当一个类从多个类派生而来时,就称为多继承。多继承时派生类定义的形式如下:class :【,】成员;8.2 多继承8.2.2 虚基类一个类可以多次作为另一个类的间接基类,但C规定,一个类不能多次作为另一个类的直接基类,所以下面的定义错误的:
7、class D:public B,public B;8.2 多继承当一个类多次间接从一个类派生以后,这个类就保留多份间接基类的成员。在大多数情况下,我们希望这个派生类只保留一份基类的成员。这时可以定义虚基类实现:class Person;class Teacher:virtual public Person;class Student:virtual public Person;class TeacherAssiant:public Teacher,public Student;8.3 虚函数 8.3.1 虚函数的定义 虚函数是在基类中冠以关键字virtual的成员函数。虚函数是成员函数,而且
8、是非static的成员函数。它提供了一种接口界面,并且可以在一个或多个派生类中被重定义。说明虚函数的方法如下:virtual ()8.3 虚函数8.3.2 虚函数的使用 联编是指一个计算机程序彼此关联的过程。按照联编所进行的阶段不同,可分为两种:静态联编和动态联编。静态联编是指联编工作出现在编译连接阶段,这种联编又称早期联编,因为这种联编过程是在程序开始运行之前完成的。编译程序在编译阶段并不能确切知道将要调用的函数,只有在程序执行时才能确定将要调用的函数,这种联编称为动态联编,又称晚期联编。8.3 虚函数如果某类中的一个成员函数被说明为虚函数,这就意味着该成员函数在派生类中可能有不同的实现。当
9、使用这个成员函数操作指针或引用所标识对象时,对该成员函数调用采用动态联编方式,即在运行时进行关联或绑定。动态联编只能通过指针或引用标识对象来操作虚函数。如果采用一般类型的标识对象来操作虚函数,则将采用静态联编方式调用虚函数。8.3 虚函数8.3.3 纯虚函数在许多情况下,在基类中不能给出有意义的虚函数定义,这时可以把它说明成纯虚函数,把它的定义留给派生类来做。定义纯虚函数的一般形式如下:class 类名virtual 返回值类型 函数名(参数表)=0;8.3 虚函数纯虚函数是一个在基类中说明的虚函数,它在基类中没有定义,要求任何派生类都定义自己的版本。纯虚函数为各派生类提供一个公共界面。由于纯虚函数所在的类中没有它的定义,在该类的构造函数和析构函数中不允许调用纯虚函数,否则会导致程序运行错误。但其他成员函数可以调用纯虚函数。8.4 多态性多态性是由C在编译时和运行时支持的。编译时多态性是由重载函数和重载运算符支持的。运行时多态性则是通过使用继承和虚函数完成的。