定义基类
//基类通常都应该定义一个虚析构函数,即使该函数不执行任何实际操作也是如此。
//基类必须将它的两种成员函数区分开来,
//一种是基类希望其派生类进行覆盖的函数,既虚函数,使用virtual关键字
//一种是基类希望派生类直接继承而不要改变的函数
class Quote
{
public:
Quote() = default;
Quote(const string& book, double sa_price) :bookNo(book), price(sa_price)
{}
virtual double net_price(int n) const
{
return n * price;
}
virtual ~Quote() = default;//对析构函数动态绑定
private:
string bookNo;
protected:
double price = 0.0;
};
定义派生类
//派生类必须通过使用类派生列表明确指出它是从那个(那些)基类继承而来。
//类派生列表是冒号后边以逗号隔开的基类列表,可以在每个基类前加访问说明符。
//派生类必须将继承而来的需要覆盖的函数重新声明。
//一个派生类对象包含多个组成部分,一个是派生类自己定义的成员,和继承来的基类的成员。
//如果派生类没有覆盖其基类中的某个虚函数,则该虚函数的行为类似于其他普通成员,派生类会直接继承其在基类中的版本。
//派生类也必须使用基类的构造函数来初始化它的基类部分。
class Bulk_quote : public Quote
{
public:
Bulk_quote() = default;
Bulk_quote(const string&, double, int, double);
double net_price(int) const override;
~Bulk_quote();
private:
int min_qty = 0;
double discount = 0.0;
};
//每个类控制自己的成员初始化过程
//首先初始化基类的成员部分,然后按照声明的顺序依次初始化派生类的成员
Bulk_quote::Bulk_quote(const string& book, double p, int qty, double disc) :
Quote(book, p), min_qty(qty), discount(disc) {}
//派生类可以访问基类的共有成员和受保护成员
double Bulk_quote::net_price(int n) const
{
if (n >= min_qty) return n * (1 - discount) * price;
else return n * price;
}
Bulk_quote::~Bulk_quote()
{}
void ShowPrice(const Quote& quote)
{
cout << quote.net_price(0) << endl;
}
int main()
{
面向对象程序设计
//核心思想是数据抽象、继承和动态绑定
//通过继承联系在一起的类构成一种层次关系为继承关系
//基类:通常在层次关系的根部,其他类直接或间接地从基类继承而来。
//派生类:这些继承得到的类称为派生类。
//基类负责定义在层次关系中所有类共同拥有的成员,而每个派生类定义各自特有的成员。
//因为在派生类中有与基类对应的组成部分,所以可以将基类的指针或引用绑定到派生类对象中的基类部分。
Quote item;//基类对象
Bulk_quote bulk;//派生类对象
Quote* p = &item;//指向Quote对象的指针
p = &bulk;//p指向bulk的Quote部分
Quote& t = bulk;//r绑定到bulk的Quote部分
//使用动态绑定,可以在一定程度上忽略相似类型的区别,而以统一的方式使用它们的对象。
//在使用基类的引用或指针调用一个虚成员函数时会执行动态绑定。
ShowPrice(item);//使用的是Quote的net_price
ShowPrice(bulk);//使用的是Bulk_quote的net_price
//函数的运行版本由实参决定,在运行时选择执行的版本,动态绑定就称为运行时绑定。
继承与静态成员
//如果基类继承了静态成员,则在整个继承体系中只存在该成员的唯一定义。
//如果基类的静态成员是private的,则派生类不能访问。
//防止继承的发生,可以类名字后跟一个关键字final。
//class Base final{}//Base不能作为基类,应为它不能被继承,成员函数和成员变量都可以用final来修饰。
类型转换与继承
//在使用继承关系时要区分表达式的静态类型和动态类型。静态在编译时总是已知的,动态类型在运行时才可知。
//不存在从基类向派生类的隐式类型转换
//对象之间不存在类型转换,派生类向基类的自动类型转换只对指针或引用有效。
//当我们用过一个派生类对象为一个基类对象初始化或赋值时,只有该派生类对象中的基类部分会被拷贝、移动或赋值,派生类的其他部分将被忽略掉。
//派生来向基类的类型转换也可能会由于访问受限而不成功。
Bulk_quote bbulk;//派生类对象
Quote iitem(bbulk);//使用的是派生类中的基类部分初始化的Quote构造函数
iitem = bbulk;//调用的是Quote::operator=(const Quote&)
return 0;
}