7.多继承
(1)多重继承派生类(多基派生类)的定义格式:
class 派生类名 : 继承方式 基类名1,继承方式 基类名2,…,继承方式 基类名n
{ 派生类中新成员的声明 };
首部出现的每一个“继承方式”,只用于限制对紧随其后的基类的继承。
首部出现的基类均为该派生类的直接基类。
派生类定义中的基类顺序决定了基类成员的构造顺序
生类的成员:继承的各基类成员+派生类增加的新成员
(2)多基派生类构造函数的定义格式:
派生类名::派生类名(形参表):基类名1(参数表1),
基类名2(参数表2),……,基类名n(参数表n)
{ 函数体 }
说明:当基类中定义有缺省参数的构造函数或未定义构造函数时,派生类构造函数的定义中可以省略对基类构造函数的调用。当基类中定义了有参构造函数时,派生类必须定义构造函数,建议是带参构造函数,提供将参数传递给基类构造函数的途径。
(3)多基派生类构造函数的调用顺序
多重继承派生类构造函数的调用顺序与单继承相同:
①先执行各基类的构造函数,处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指的各基类顺序。
②然后执行对象成员的构造函数;
③最后执行派生类的构造函数。
(4)多基派生类析构函数的调用顺序:与构造函数严格相反。
(5)二义性
①同名成员:
当一个派生类的多个直接基类声明了同名的成员时
解决方法:用基类名和作用域运算符来限定
②多基类为同一基类派生:
当派生类从多个基类派生,而这些基类又是从同一个基类派生而得,则在访问此共同基类的成员时
解决方法:用基类名和作用域运算符来限定、采用虚基类来解决
③虚基类
虚基类并不是一种新的类型的类,而是一种派生的方式。如果采用虚基类的方式定义派生类,在创建派生类对象时,类层次结构中某个虚基类的子对象只被保留一个。
将一个基类声明为虚基类,必须在定义各直接派生类时,在指定基类名前面加上关键字virtual,定义格式:
class 派生类名:virtual 继承方式 基类名
{ 声明派生类成员 };
第5章 多态性和虚函数
1.多态性
(1)概念:
是指同样的消息被不同对象接收时导致完全不同行为的现象。这里的“消息”即对类成员函数的调用。(以相同的指令却调用了不同的函数)
(2)种类:
①编译时的多态性:静态联编
不论用类对象、对象指针或对象引用哪种形式访问成员函数(非虚函数),编译系统都根据它们的定义类型,在编译阶段进行静态绑定。其方式为:
通过在类中重载成员函数实现
通过在派生类中重定义基类成员函数实现
②运行时的多态性:动态联编
运行时的多态性是指在程序运行时根据运行所产生的信息决定调用哪个函数,它是在运行过程中发生的,编译系统在编译时是无法确定的,通过虚函数实现。
2.虚函数的定义与调用
(1)虚函数实现多态性的过程:
首先将基类中的某成员函数声明为虚函数,然后在每个派生类中重新定义此虚函数。当客户通过基类指针(或引用)请求调用虚函数时,C++会在程序运行时根据所指对象的不同,自动地选择与之关联的派生类函数,实现调用。
(2)基类中声明虚函数的方法:
class 类名
{ ……
virtual 类型 函数名(参数表);
……
};
(3)说明:
①只有类的成员函数才能被声明为虚函数,其他全局函数和静态成员函数、类的构造函数不能声明为虚函数。
②若虚函数在类外定义,则定义时不能再加virtual关键字
③虚函数可以在多个派生类中被重定义,它属于函数重载的情况。但与一般函数重载不同的是,它要求在派生类中重定义时的虚函数必须与基类定义中的虚函数原型完全相同。否则,按普通函数重载看待。
④一旦一个基类成员函数被声明为虚函数,它从该点之后的继承层次结构中都是虚函数。若派生类需重定义该虚函数,声明时可省略virtual关键字。
⑤没有重定义虚函数的派生类简单地继承其直接基类的虚函数。
⑥C++只对调用的虚函数进行动态绑定,而普通函数则是静态绑定。
3.虚析构函数
(1)虚析构函数解决的问题:
若基类指针指向的派生类对象是使用new运算动态生成的,如果没有将析构函数定义为虚函数,则在使用delete运算删除该派生类对象时,只会调用基类析构函数,而没有调用派生类的析构函数,从而无法完成正确的对象清理工作。
(2)说明:
如果将基类的析构函数定义为虚函数,由该基类所派生的所有派生类的析构函数也都自动成为虚函数。
4.纯虚函数与抽象类
(1)纯虚函数:
只在基类中声明为虚函数,但未给出具体的函数定义。纯虚函数的声明形式:
virtual 类型 函数名(参数表)=0;
(2)抽象类:包含纯虚函数的类称为抽象类。
(3)说明:
不能建立抽象基类的实例化对象,但可以声明指向抽象基类的指针变量或引用,用以实现虚函数的运行时多态。
抽象类中可以有多个纯虚函数。
抽象类也可以定义其他非纯虚函数。
如果在派生类中没有重新定义纯虚函数,则必须再次将该虚函数声明为纯虚函数,此时这个类仍是一个抽象类。
从抽象类中可以派生出具体类或抽象类,但不能从具体类派生出抽象类。