继承
通过继承联系在一起的类构成一种层次结构,根部的为基类,其他类为派生类。基类负责定义在层次关系中,所有类共同拥有的成员。派生类定义各自特有的成员。
虚函数
基类将类型相关的函数与派生类不做改变直接继承的函数区别对待。对于某些函数,基类希望派生类定义自己合适的版本,此时基类将这些函数声明为虚函数。 派生类必须在其内部对 所有重新定义的虚函数进行声明 。
在C++11新标准中,我们可以使用override关键字来说明派生类中的虚函数。如果某个函数标记了override关键字,但该函数并没有覆盖已存在的虚函数,则编译器会报错。
class Quote
{
public:
string isbn() const;
virtual double net_price(size_t n) const;//虚函数
};
class Bulk_quote : public Quote
{
public:
double net_price(size_t n) const override;
};
动态绑定
double print_total(ostream& os, const Quote& item, size_t n)
{
double ret = item.net_price(n);
os << "ISBN:" << item.isbn()
<< "#sold: " << n << "total due: " << ret << endl;
}
这个函数有两个有趣的事实。
- 因为该函数形参item是基类Quote的一个引用,我们既能使用基类Quote的对象调用该函数,也能使用派生类Bulk_quote的对象调用它。
- 当我们用Quote对象调用net_price时,则调用的是Quote版本的net_price。当用Bulk对象调用时,则调用的是Bulk版本的net_price。这也称为运行时绑定
在C++中,当我们使用基类的引用或指针调用一个虚函数时,将发生动态绑定。
作为继承关系中根节点的类通常都会定义一个虚析构函数。
基类通常都应该定义一个虚析构函数,即使该函数不执行任何实际操作也是如此
。
基类
class Quote
{
public:
Quote() = default;
Quote(const string& s,double sales_price):bookNo(s),price(sales_price){}
string isbn() const;
virtual double net_price(size_t n) const;//虚函数
virtual ~Quote() {}//对析构函数进行动态绑定
private:
string bookNo;
protected:
double price = 0.0;
};
派生类
派生类可以继承其基类成员,但当遇到net_price这样与类型相关的操作时,派生类必须对其重新定义。
换句话说:派生类需要对这些操作提供自己的新定义以覆盖从基类继承而来的旧定义
关键字virtual只能出现在类的内部,不能出现在类的外部。override同样也是
我们能将公有派生类的对象绑定到基类的引用或指针上。
派生类经常覆盖它继承的虚函数,如果派生类没有覆盖,派生类会直接继承其在基类的版本
派生类对象及派生类向基类类型的转化:
因为在派生类对象中,含有与其基类对应的组成部分,因此可以把派生类对象当作基类对象来使用,而且我们也能将基类的指针和引用绑定到派生类对象的基类部分。
Quote item;
Bulk_quote bulk;
Quote *p = &bulk;
Quote &r = bulk;
我们可以把派生类对象或者派生类对象的引用用在需要基类引用的地方
同样,也可以把派生类对象的指针用在基类指针的地方。
派生类构造函数
派生类必须使用基类的构造函数来初始化它的基类部分。每个类控制他自己的成员初始化过程。
Bulk_quote(const string& s, double prc, size_t min, double disCount):
Quote(s,prc),min_count(min),discount(disCount){}
初始化顺序:先执行Quote初始化,然后是Quote的函数体,然后是Bulk_quote的初始化,再执行Bulk_quote函数体。
bookNo虽然派生类不能使用,但初始化的时候要对它初始化。
派生类可以访问基类公有和受保护成员
double Bulk_quote::net_price(size_t n) const
{
if (n >= min_count)
{
return n * (1 - discount) * price;
}
else
{
return n * price;
}
}
继承与静态成员
如果基类定义了一个静态成员,则在整个继承体系中,只存在该成员唯一定义。
无论从基类派生出多少个派生类,都只有唯一实例。
同时静态成员遵循访问控制。我们可以通过
- 基类::静态函数()
- 派生类::静态函数()
- 对象
来访问静态成员。
防止继承发生
我们有时不希望其他类继承我们的类,在C++11新标准中提供了一种防止继承的新方法,即在类名后跟一个关键字final。
class NoDerived final
{}
class Bad : NoDerived
{}
这种做法是错误的。有final的关键字是不允许被继承的。
今天就到这儿吧,最后把运行结果贴一下
Quote.h
#pragma once
#include<iostream>
#include<string>
using namespace std;
class Quote
{
public:
Quote() = default;
Quote(const string& s,double sales_price):bookNo(s),price(sales_price){}
string isbn() const;
virtual double net_price(size_t n) const;//虚函数
virtual ~Quote() {}//对析构函数进行动态绑定
private:
string bookNo;
protected:
double price = 0.0;
};
ostream& print_total(ostream& os, const Quote& item, size_t n);
Quote.cpp
#include "Quote.h"
ostream& print_total(ostream& os, const Quote& item, size_t n)
{
double ret = item.net_price(n);
os << "ISBN:" << item.isbn()
<< " #sold: " << n << " total due: " << ret << endl;
return os;
}
string Quote::isbn() const
{
return bookNo;
}
double Quote::net_price(size_t n) const
{
return n * price;
}
Bulk_quote.h
#pragma once
#include "Quote.h"
using namespace std;
class Bulk_quote : public Quote
{
public:
Bulk_quote() = default;
Bulk_quote(const string& s, double prc, size_t min, double disCount):
Quote(s,prc),min_count(min),discount(disCount){}
double net_price(size_t n) const override;
private:
size_t min_count = 0;
double discount = 0.0;
};
Bulk_quote.cpp
#include "Bulk_quote.h"
double Bulk_quote::net_price(size_t n) const
{
if (n >= min_count)
{
return n * (1 - discount) * price;
}
else
{
return n * price;
}
}
More_quote.h
#pragma once
#include "Quote.h"
class More_quote :public Quote
{
public:
More_quote() = default;
More_quote(const string& s,double price,size_t more,double dis):
Quote(s,price),moreCount(more),discount(dis) {}
double net_price(size_t n) const override;
private:
size_t moreCount = 0;
double discount = 0.0;
};
More_quote.cpp
#include "More_quote.h"
double More_quote::net_price(size_t n) const
{
if (n <= moreCount)
{
return n * price * (1 - discount);
}
else
{
return moreCount * price * (1 - discount) + (n - moreCount) * price;
}
}
quote_test.cpp
#include<iostream>
#include"Quote.h"
#include"Bulk_quote.h"
#include"More_quote.h"
using namespace std;
int main()
{
Quote q("dangdang", 100);
Bulk_quote b("cc", 100, 10, 0.1);
More_quote e("aa", 100, 5, 0.1);
print_total(cout, q, 10);
print_total(cout, b, 10);
print_total(cout, e, 10);
}