15.5抽象基类

抽象基类

假设书店有几种不同的折扣策略,除了购买量超过一定数量享受折扣外;也有购买量不超过某个限额可以享受折扣,但超过就会原价销售;还有不超过某个购买数量原价销售,超过某个数量超出的部分才打折。

上面这些打折策略都要求一个购买量和一个折扣值。我们可以定义一个DiscQuote类来支持不同的打折策略,DiscQuote类的意义就是打折的概念类。负责保存购买量的值和折扣值。其他类表示某种特定的打着策略类,将继承DiscQuote类。

DiscQuote类与任何特定的折扣策略都无关,因此DiscQuote类的netPrice函数没有实际意义,我们可以将其定义为纯虚函数。

我们先定义这些类

class Quote {
public:
	Quote() = default;
	Quote(const string s, double price):_bookNo(s), _price(price){}
	string isbn() const {
		return _bookNo;
	}
	virtual double netPrice(int n) const {
		return n * _price;
	}
protected:
	double _price;
private:
	string _bookNo;
};
class DiscQuote : public Quote{
public:
	DiscQuote():Quote(), _minBuy(0), _disc(0.0){}
	DiscQuote(string bookNo, double price, int minBuy, double disc):
		Quote(bookNo, price), _minBuy(minBuy), _disc(disc){}
	double netPrice(int n) const = 0;
protected:
	int _minBuy = 0;
	double _disc = 0;
};
class BulkQuote : public DiscQuote {
public:
	BulkQuote():DiscQuote(){}
	BulkQuote(string bookNo, double price, int minBuy, double disc):
		DiscQuote(bookNo, price, minBuy, disc){}
	double netPrice(int n) const override {
		if (n > _minBuy) {
			return n * _disc * _price;
		} else {
			return n * _price;
		}
	}
};

①纯虚函数

我们不希望创建一个DiscQuote对象,因为DiscQuote类表示的是一本书打折的概念,而非具体的折扣策略,创建DiscQuote类没有意义。

我们可以将netPrice定义成纯虚函数来清晰的告诉用户这个netPrice函数是没有任何意义的。纯虚函数无需定义,只要在函数体的位置书写=0就可以将一个虚函数说明为纯虚函数。 如:

DiscQuote::double netPrice(int n) const = 0;

②含有纯虚函数的类是抽象基类

含有纯虚函数的类是抽象基类。抽象基类负责定义接口,而后续的其他类可以覆盖该接口。

我们不能创建一个抽象基类的对象,因为抽象基类有纯虚函数,我们可以定义抽象基类的派生类对象,前提是这些类覆盖了纯虚函数,如果没有覆盖那么派生类也是抽象基类。但是,可以创建抽象基类的引用或指针绑定其派生类对象。

如:

//DiscQuote声明了纯虚函数,BulkQuote覆盖了纯虚函数
DiscQuote disc;           //错误:不能定义一个纯虚函数的对象 
BulkQuote bulk;           //正确:BulkQuote没有纯虚函数
DiscQuote *discp = &bulk; //正确
DiscQuote &disr = bulk;   //正确

③派生类构造函数只初始化它的直接基类

如:BulkQuote的构造函数

	BulkQuote():DiscQuote(){}
	BulkQuote(string bookNo, double price, int minBuy, double disc):
		DiscQuote(bookNo, price, minBuy, disc){}

BulkQuote的直接基类是DiscQuote,间接基类是Quote。每个类各自控制其对象的初始化过程,即使BulkQuote没有自己的数据成员,仍然需要提供一个接受4个参数的构造函数,通过将它的参数传递给DiscQuote的构造函数,DiscQuote的构造函数会继续调用Quote的构造函数来初始化这四个参数。

④可以通过基类的指针或引用绑定其派生类的派生类的对象调用虚函数实现多态

如:

int main() {
	BulkQuote bq("abc", 50, 10, 0.8);
	Quote &dk = bq;
	cout << dk.netPrice(20);
}

Quote是BulkQuote的间接父类,但也可以调用BulkQuote的虚函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值