面向对象基础

定义基类和派生类

定义基类

基类通常都应该定义一个虚析构函数,即使该函数不执行任何实际操作也是如此。
C++中,基类必须将它的两种成员函数区分开来:一种是基类希望其派生类进行覆盖的函数;另一种是基类希望派生类直接继承而不要改变的函数。对于前者,基类通常将其定义为虚函数。当我们使用指针或引用调用虚函数时,该调用将被动态绑定。根据引用或指针所绑定的对象类型不同,该调用可能执行基类的版本,也可能执行某个派生类的版本。
基类通过在其成员函数的声明语句之前加上virtual使得该函数执行动态绑定。任何构造函数之外的非静态函数都可以是虚函数。如果基类把一个函数声明成虚函数,则该函数在派生类中隐式地也是虚函数。

定义派生类

如果一个派生是公有的,则基类的公有成员也是派生类接口的组成部分。此外,我们能将公有派生类型的对象绑定到基类的引用或指针上。
派生类如果没有覆盖其基类的某个虚函数,则该函数的行为类似于其他的普通成员,派生类会直接继承其在基类中的版本。C++11允许派生类显示地注明它使用某个成员函数覆盖它继承的虚函数,关键字override

派生类对象及派生类向基类的类型转换

因为在派生类对象中含有与其基类对应的组成部分,所以我们能把派生类的对象当成基类对象来使用,而且我们也能将基类的指针或引用绑定到派生类对象的基类部分上。

Quote item;
Bulk_quote bulk;
Quote *p = &item;
p = &bulk;
Quote &r = bulk;

派生类构造函数

派生类必须使用基类的构造函数来初始化它的基类部分。
除非我们默认指出,否则派生类对象的基类部分会像数据成员一样执行默认初始化。
首先初始化基类部分,然后按照声明的顺序依次初始化派生类的成员。

关键概念:遵循基类的接口
必须明确一点:每个类负责定义各自的接口。要想与类的对象交互必须使用该类的接口,即使这个对象是派生类的基类部分也是如此。尽管从语法上来说我们可以在派生类构造函数体内给它的公有或受保护的基类成员赋值,但是最好不要这么做。和使用基类的其他场合一样,派生类应该遵循基类的接口,并且通过调用基类的构造函数来初始化那些从基类中继承而来的成员。

继承与静态成员

如果基类定义了一个静态成员,则在整个继承体系中只存在该成员的唯一定义。

被用作基类的类

如果我们想将某个类用作基类,则该类必须已经定义而非仅仅声明。

防止继承的发生

在类名后加关键字final

类型转换与继承

可以将基类的指针或引用绑定到派生类对象上有一层极为重要的含义:当使用基类的指针或引用时,实际上我们并不清楚该引用所绑定对象的真实类型。

不存在从基类到派生类的隐式类型转换。

即使一个基类指针或引用绑定在一个派生类对象上,我们也不能执行从基类向派生类的转换:

Bulk_quote bulk;
Quote* itemP = &bulk;
Bulk_qoute* bulkP = itemP;//错误

编译器在编译时无法确定某个特定的转换在运行时是否安全,这是因为编译器只能通过检查指针或引用的静态类型来推断该转换是否合法。如果在基类中含有一个或多个虚函数,我们可以使用dynamic_cast请求一个类型转换,该转换的安全检查将在运行时执行。同样,如果我们已知某个基类向派生类的转换是安全的,则我们可以使用static_cast来强制覆盖掉编译器的检查工作。

当我们用一个派生类对象为一个基类对象初始化或赋值时,只有该派生类对象中的基类部分会被拷贝、移动或赋值,它的派生类部分将被忽略掉。

关键概念:存在继承关系的类型之间的转换规则
要想理解在具有继承关系的之间发生的类型转换,有三点非常重要:

  • 从派生类向基类的类型转换只对指针或引用类型有效
  • 基类向派生类不存在隐式类型转换
  • 和任何其他成员一样,派生类向基类的类型转换也可能会由于访问受限而变得不可行

虚函数

对虚函数的调用可能在运行时才被解析

动态绑定只有当我们通过指针或引用调用虚函数才会发生。

关键概念:C++多态性
OOP的核心思想是多态性,含义是多种形式。我们把具有继承关系的多个类型称为多态类型,因为我们能使用这些类型的多种形式而无须在意它们的差异。

派生类中的虚函数

一个派生类的函数如果覆盖了某个继承而来的虚函数,则它的形参必须完全一致。同样,派生类中虚函数的返回类型也必须与基类函数匹配。当类的虚函数返回类型是类本身的指针或引用时,上述规则无效。如果DB派生得到,则基类的虚函数可以返回B*而派生类的对应函数可以返回D*,只不过这样的返回类型要求从DB的类型转换是可访问的。

final和override

回避虚函数的机制

``c++
double undiscounted = baseP->Quote::net_price(42);//强行调用
Quotenet_price函数,而不管baseP`实际指向的对象类型到底是什么。

抽象基类

纯虚函数

和普通的虚函数不一样,一个纯虚函数无需定义。我们通过在函数体的位置(即在声明语句分号前)书写=0就可以将一个虚函数说明为纯虚函数。其中,=0只能出现在类内部的虚函数声明语句处。

含有纯虚函数(或者未经覆盖直接继承)的类是抽象基类。

抽象基类负责定义接口,而后续的其他类可以覆盖该接口。我们不能直接创建一个抽象基类的对象。

派生类构造函数值初始化它的直接基类

访问控制与继承

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值