面向对象程序设计的核心思想是数据抽象、继承和动态绑定。 通过使用数据抽象,我们可以将类的接口与实现分离; 使用继承,可以定义相似的类型并对其相似关系建模; 使用动态绑定,可以在一定程度上忽略相似类型的区别,而以统一的方式使用它们的对象。
继承
通过继承(inheritance)联系在一起的类构成一种层次关系。通常在层次关系的根部有一个基类(base class),其他类则直接或间接地从基类继承而来,这些继承得到的类称为派生类(derived class)。基类负责定义在层次关系中所有类共同拥有的成员,而每个派生类定义各自特有的成员。
对于某些函数,基类希望派生类各自定义适合自身的版本,此时基类就将这些函数声明为虚函数。派生类需要对这些操作提供自己的新定义以覆盖(override)从基类继承而来的旧定义。
派生类通过类派生列表明确指出它是从哪个(哪些)基类继承而来。类派生列表的形式是:首先是一个冒号,后面紧跟以逗号分隔的基类列表,其中每个基类前面可以有访问说明符。
动态绑定
通过使用动态绑定(dynamic binding),我们能用同一段代码分别处理基类和派生类的对象。print_total函数传入形参是基类的引用类型,而实际我们既能传基类实参又能传派生类实参。根据实际传入的对象类型将决定到底执行net_price()的哪个版本:如果传的是基类类,则调用Quote::net_price();如果传的是派生类,则调用Bulk_quote::net_price()。因为在上述过程中函数的运行版本由实参决定,即在运行时选择函数的版本,所以动态绑定有时又被称为运行时绑定(run-time binding)。
在C++语言中,当我们使用基类的引用(或指针)调用一个虚函数时将发生动态绑定。
//basic的类型是Quote; bulk的类型是Bulk_quote
print_total(cout, basic, 20); //调用Quote的net price
print_total(cout, bulk, 20); //调用Bulk quote的net_price成员函数与继承
基类通过在其成员函数的声明语句之前加上关键字virtual使得该函数执行动态绑定。任何构造函数之外的非静态函数都可以是虚函数。关键字virtual只能出现在类内部的声明语句之前而不能用于类外部的函数定义。如果基类把一个函数声明成虚函数,则该函数在派生类中隐式地也是虚函数。
成员函数如果没被声明为虚函数,则其解析过程发生在编译时而非运行时。
class Quote {
public:
Quote() = default;
Quote(const std::string &book, double sales_price) : bookNo(book), price(sales_price) {}
std::string isbn() const { return bookNo; };
virtual double net_price(std::size_t n) const { return n * price; };
virtual ~Quote() = default;
private:
std::string bookNo;
protected:
double price = 0.0;
};
class Bulk_quote : public Quote {
public:
Bulk_quote() = default;
Bulk_quote(const std::string &book, double p, std::size_t qty, double disc)
: Quote(book, p), min_qty(qty), discount(disc) {}
double net_price(std::size_t) const override;
double print_total(std::ostream &os, const Quote &item, size_t n) {
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << std::endl;
return ret;
}
private:
std::size_t min_qty = 0;
double discount = 0.0;
};
double Bulk_quote::net_price(std::size_t cnt) const {
if (cnt >= min_qty) {
return cnt * (1 - discount) * price;
} else {
return cnt * price;
}
}