首页 > 学院 > 开发设计 > 正文

类继承

2019-11-10 22:56:04
字体:
来源:转载
供稿:网友

常见为公有派生:

class RatedPlayer : public TableTennisPlayer

{..}

冒号表明,RatedPlayer的基类是TableTennisPlayer。使用公有派生,基类的公有部分将称为派生类的公有部分,基类的私有部分将称为派生类的一部分,但不能被派生类直接访问,只能通过基类的公有和保护方法访问。派生类需要自己的构造函数,并根据需要添加额外的数据成员和成员函数。

创建派生类对象时,首先调用基类构造函数,然后再调用派生类的构造函数。基类构造函数负责初始化继承的数据成员,派生类构造函数主要用于初始化新增的数据成员。派生类的构造函数总是调用一个基类的构造函数。可以使用初始化列表语法指明要使用的基类构造函数,否则将使用默认的基类构造函数。

派生类对象过期时,先调用派生类的析构函数,再调用基类析构函数。

使用派生类程序必须能够访问到基类。由于两个类是相关的,一般将他们的声明放在同一个.h文件中。

基类指针可以在不进行显式类型转换的情况下指向派生类对象;基类引用可以在不进行显式类型转换的情况下引用派生类对象,但不能反过来,即不能将基类对象和地址赋给派生类引用或指针。基类指针或引用只能用于调用基类方法(声明了虚方法后,可以用于调用同名覆盖的派生类方法)。

公有继承是一种is-a关系。

虚函数——多态重要机制:在方法声明前加上virtual关键字,声明为虚方法,则它在派生类中将自动成为虚方法。然而在派生类中最好也加上virtual声明指出来,看着方便。virtual只用于类声明的方法原型中,定义中不需要。

如果没有使用虚方法,在调用同名的方法时,程序将根据引用类型或指针类型选择方法;如果使用了虚方法,程序将根据引用或指针指向的对象的类型来选择方法。

通常,基类需要声明虚析构函数。如果析构函数不是虚的,则将只调用对应于指针类型的析构函数,即使其指向的是派生类对象。因此为确保正确释放派生对象时,按正确的顺序调用析构函数,需要声明虚析构函数。

编译器对非虚方法使用静态联编,即在编译时就能确定使用的是哪一个函数;对虚方法使用动态联编,即在程序运行时选择使用哪一个函数。为避免额外的处理开销,默认为静态联编。所谓的开销是指在内存和执行速度方面有一定的成本:

1、每个对象都将增大,增大量为存储地址的空间;

2、对于每个类,编译器都创建一个虚函数地址表(数组);

3、对于每个函数调用,都需要执行一项额外的操作,即到表中查找地址。

虚函数表中存储了为类对象进行声明的虚函数的地址。例如,基类对象包含一个指针(形如隐藏的成员),指向基类中所有虚函数的地址表。派生类对象将包含一个指向独立地址表的指针。如果派生类提供了虚函数的新定义,该表将保存新函数的地址;如果没有重新定义虚函数,该表将保存函数原始版本的地址。如果派生类定义了新的虚函数,则该函数的地址也被添加到该表中。

构造函数不能是虚函数。创建派生类对象时,将调用派生类的构造函数,然后其将使用基类的一个构造函数,这种顺序不同于继承机制。因此,派生类并不继承基类的构造函数。

析构函数应当是虚函数,即使它不执行任何操作,除非类不用做基类。

友元不能是虚函数,因为友元不是类成员,只有成员函数才能是虚函数。

如果派生类没有重新定义函数,将使用该函数的基类版本。如果派生类位于派生链中,则将使用最新的虚函数版本,例外情况是基类版本是隐藏的(被覆盖)。

如果派生类有重新定义函数,不会生成函数的两个重载版本,而是隐藏了基类版本。将不是使用相同的函数特征标覆盖基类声明,而是隐藏同名的基类方法,不管参数特征标如何。

PRotect成员表示,派生类的成员可以直接访问基类的保护成员,但不能访问基类的私有成员。即,对于外部世界来说,保护成员的行为与私有成员类似;而对于派生类来说,保护成员的行为与公有成员相似。

抽象基类:

通过纯虚函数提供未实现的函数。纯虚函数的声明前面为virtual关键字,结尾处为 = 0(如果有const,则结尾为const = 0)。当类声明包含纯虚函数时,则不能创建该类的对象。这里的理念是,包含纯虚函数的类只能用作基类,即抽象基类。抽象基类至少包含一个纯虚函数。在类中允许不定义纯虚函数。

如果在派生类中仍没有实现纯虚函数定义,则仍为抽象类,不能实例化。

抽象基类(或叫ABC)看作是一种必须实施的接口。ABC要求具体派生类覆盖其纯虚函数——迫使派生类遵循ABC设置的接口规则,即接口约定。这样确保了从ABC派生的所有组件都至少支持ABC指定的功能。

继承和动态内存分配的问题:假设基类成员包含指针,构造函数使用了动态内存分配(即new),且声明中包含了构造函数使用new时需要的特殊方法:析构函数、复制构造函数和重载赋值运算符。如果派生类不使用new,则不再需要为派生类定义显式析构函数、复制构造函数和赋值运算符。反之,如果派生类使用了new,则必须为派生类定义显式析构函数、复制构造函数和赋值运算符。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表