继承与动态绑定
2024年1月5日 2024年1月5日
面向对象程序设计 object-oriented programming
的核心思想:
- 数据抽象
将类的接口与实现分离 - 继承
定义相似的类型并对其相似关系建模 - 动态绑定
在一定程度上忽略相似类型的区别, 以统一的方式使用它们的对象
继承
inheritance
通过继承联系在一起的类构成一种层次关系. 层次关系的根部有一个基类 base class
, 其他类直接或间接地从基类继承而来, 这些继承得到的类称为派生类 derived class
.
基类负责定义在层次关系中所有类共同拥有的成员, 而每个派生类定义各自特有的成员
虚函数
virtual function
基类将类型相关的函数与派生类不作改变直接继承的函数区分对待
对于某些函数, 基类希望它的派生类各自定义适合自身的版本, 基类会将这些函数声明为虚函数, 使用关键字 virtual
作为继承关系中根节点的类通常会定义一个虚析构函数
net_price和析构函数均为虚函数
1class Quote 2{ 3public: 4 Quote() = default; 5 Quote(const string &book, double sales_price) : bookNo(book), price(sales_price) {} 6 string isbn() const { return bookNo; } 7 virtual double net_price(size_t n) const { return n * prices; } 8 virtual ~Quote() = default; 9private: 10 string bookNo; 11protected: 12 double price = 0.0; 13};
类派生列表
class derivation list
明确指出类是从哪个(哪些)基类继承而来. 每个基类前面都可以有访问说明符
1class Bulk_quote : public Quote 2{ 3public: 4 Bulk_quote() = default; 5 Bulk_quote(const string &, double, size_t, double); 6 virtual double net_price(size_t) const override; 7private: 8 size_t min_qtry = 0; 9 double discount = 0.0; 10};
派生类覆写基类的虚函数
如果派生类需要重新实现基类的虚函数, 需对虚函数进行声明, 使用 override
关键字
声明时, 建议同样给出 virtual
关键字, 表明是对虚函数进行覆写
动态绑定
dynamic binding
- Bulk_quote作为Quote的派生类
- 一个接受Quote对象(使用引用绑定)的函数, 同样可以接受Bulk_quote对象: print_total函数对引用调用net_price函数
1double print_total(ostream &os, const Quote &item, size_t n) 2{ 3 double ret = item.net_price(n); 4 os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << endl; 5 return ret; 6}
- 派生类Bulk_quote对基类虚函数net_price进行了覆写
当我们传入Quote对象时, print_total调用Quote::net_price; 如果我们传入Bulk_quote对象, print_total调用Bulk_quote::net_price
1Quote basic; 2Bulk_quote bulk; 3 4print_total(cout, basic, 20); // Quote::net_price 5print_total(cout, bulk, 20); // Bulk_quote::net_price
上述过程中函数的运行版本由实参决定, 即在运行时选择函数的版本, 所以动态绑定也被称作运行时绑定 run-time binding
在C++语言中, 当我们使用基类的引用(或指针)调用一个虚函数时将发生动态绑定