前言
面向对象有三个核心概念,抽象、继承、多态。
数据抽象就是多类事物的共同特征抽象出来,抽象出一个类,这个类定义了接口。
继承是描述类与类之间的关系,是一种包含关系。比如苹果和梨子都是水果,水果是基类,它包含苹果和梨子的共同特征(数据特征、行为特征),而苹果和梨是派生类,有它们自己独有的特征。
多态,c++主要指的是动态绑定,根据里氏替换原则,使用父类的地方都可以用子类去替换。在运行时,根据实际类型(c++称为动态类型)来调用实际类型的方法,已达到复用的目的。
我们在之前 类 的那一章已经分析过数据抽象的基本知识了。本文主要分析继承和动态绑定(更加严格来说)。
继承和动态绑定对程序有两方面的影响:
- 更容易的定义与其他类相似但不完全相同的新类 (继承)
- 在一定程度上忽略这些彼此相似的类编写程序(动态绑定)
// 继承
class Quote {
public:
std::string isbn() const;
// 希望派生类定义自己的版本
virtual double net_price(int n) const;
};
class Bulk_quote : public Quote {
public:
// 1. virtual 可加可不加;2.override显示的告诉编译器这个方法重写了基类的虚函数
virtual double net_price(int n) const override;
};
// 动态绑定
double print_total(ostream &os, const Quote &item, int n) {
// 使用基类引用编程,运行时根据引用的动态类型选择实际类型的虚函数
double ret = item.net_price(n);
cout << ret << endl;
}
Quote basic;
Bulk_quote bulk;
print_total(cout, basic, 20); // 调用 Quote::net_price
print_total(cout, bulk, 20); // 调用 Bulk_quote::net_price
注意:
c++ 中,使用基类的引用或者指针调用虚函数来发生动态绑定
1. 定义基类和派生类
- 基类
基类集中了派生类共有的特征,通过将函数设置成虚拟函数来说明希望派生类定义自己的版本,而如果派生类没有定义自己的版本,则会继承基类的版本,并且隐式保持着虚拟的状态。
class Quote {
public:
Quote() = default;
virtual ~Quote() = default;