10.1使用继承构建类

10.1使用继承构建类

1.扩展类

当使用C++编写类定义时,可以告诉编译器,该类继承、派生或扩展了一个已有的类。通过这种方式,该类将自动包含原始类的数据成员和方法;原始类称为父类(parent class)、基类或超类(superclass)。扩展已有类可以使该类(现在称为派生类或子类)只描述与父类不同的那部分内容。

1.1客户对继承的看法

指向某个对象的指针或引用可以指向声明类的对象,也可以指向其任意派生类的对象。

1.2从派生类的角度分析继承

如果类将数据成员或方法声明为 protected,派生类就可以访问它们;如果声明为private,派生类就不能访问。

private 访问说明符可以控制派生类与基类的交互方式。建议将所有数据成员都默认声明为private,如果希望任何代码都可以访问这些数据成员,可以提供 public 的getter 和 setter。如果仅希望派生类访问它们,就可以提供 protected 的getter和 setter。把数据成员默认设置为 private 的原因是,这会提供最高级别的封装,这意味着可以改变数据的表示方式,而保持 public 或 protected 的接口不变。另外,不直接访问数据成员,也可以在 public 或 protected的setter中方便地添加对输入数据的检查。方法也应默认设置为private,只有需要公开的方法才设置为 public,只有派生类需要访问的方法才设置为protected。

在这里插入图片描述

1.3禁用继承

C++允许将类标记为 final,这意味着继承这个类会导致编译错误。将类标记为 final 的方法是直接在类名的后面使用 final关键字。

2.重写方法

从某个类继承的主要原因是为了添加或替换功能。这个方法在派生类中的行为与在基类中的相同。在许多情况下,可能需要替换或重写某个方法来修改类的行为。

2.1关键字virtual

只有基类中声明为virtual的方法才能被派生类正确地重写。关键字 virtual 出现在方法声明的开头.

派生类也是如此。如果想进一步在派生类中重写它们,相应的方法也应该标记为 virtual。

2.2重写方法的语法

为了重写某个方法,需要在派生类的定义中重新声明这个方法,就像在基类中声明的那样,但是需要添加关键字override,并从派生类中删除关键字 virtual

一旦将方法或析构函数标记为 virtual,它们在所有派生类中就一直是 virtual,即使在派生类中删除了virtual关键字,也同样如此。

2.3客户对重写方法的看法

指针或引用可指向某个类或其派生类的对象。对象本身"知道"自己所属的类,因此只要这个方法声明为 virtual,就会自动调用对应的方法。

即使基类的引用或指针知道这实际上是一个派生类,也无法访问没有在基类中定义的,定义在派生类中的方法或成员。

2.4override关键字

overide 关键字的使用是可选的,但强烈推荐使用。如果没有 override 关键字,可能会偶然创建一个新的虚方法,而不是重写基类的方法。

2.5virtual的真相

如果方法不是virtual,也可以试着重写这个方法,但是这样做会导致微妙的错误。

隐藏而不是重写

试图重写非虚方法将会"隐藏"基类定义的方法,并且重写的这个方法只能在派生类环境中使用。

如何实现virtual

为理解如何避免隐藏方法,需要了解virtual关键字的真正作用。C++在编译类时,会创建一个包含类中所有方法的二进制对象。**在非虚情况下,将控制交给正确方法的代码是硬编码,此时会根据编译期的类型调用对应的方法。**这称为静态绑定(static binding),也称为早绑定(early binding)。

如果方法声明为virtual,会使用名为虚表(vtable)的特定内存区域来调用正确的实现。**每个具有一个或多个虚方法的类都有一张虚表,这种类的每个对象都包含指向虚表的指针,这个虚表包含指向虚方法实现的指针。通过这种方法,当使用某个对象调用方法时,指针也进入虚表,然后根据实际的对象类型在运行期执行正确版本的方法。**这称为动态绑定(dynamic binding)或晚绑定(late binding)。

class Base
{
  public:
  	virtual void func1();
  	virtual void func2();
  	void nonVirtualFunc();
};

class Derived : public Base
{
  public:
  	void func2() overrid;
    void nonVirtualFunc();
};

对于这个示例, 考虑下面的两个实例:

Base myBase;
Derived myDerived;

在这里插入图片描述

使用virtual的理由

虚构函数的需求

析构函数应该都声明为 virtual。原因是,如果析构函数未声明为 virtual,很容易在销毁对象时不释放内存。唯一允许不把析构函数声明为 virtual的例外情况是,类被标记为 final。

2.6禁用重写

除了将实体类标记为 final,C++还允许将方法标记为 final。这意味着无法在派生类中重写这个方法。

  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值