15.3 虚函数
只有在基类的指针或者引用访问虚函数的时候才会发生动态绑定。 如果由一个基类或者一个派生的对象直接访问虚函数则访问的就是其自己定义的那个函数,不会发生动态绑定。此时如果想访问基类的函数则需要使用作用域运算符来访问。
重写虚函数时,返回值类型和参数列表中的参数需要完全一样,否则派生类重写的函数实际是定义了一个新的函数,为了防止开发人员误操作,C++提供了override函数,显式的表示这个函数是重写基类的。
final除了可以用来修饰类外,还可以用来修饰函数,修饰函数放在引用限定符,const,以及形参列表之后,表示这个函数不能被重写。
对于重写的虚函数,如果虚函数中由默认实参,则使用基类的指针或者引用,访问该虚函数时,不管对象是否是基类,使用的都是基类的默认实参。 所以我们应该尽量避免在虚函数中写默认实参,或者在虚函数中使用一样的实参。
练习
15.11
在派生类中需要使用作用域运算符来访问基类的debug函数。
string Quote::debug() const
{
ostringstream str("");
str << "BookNo:" << bookNo << ",Price" << price;
return str.str();
}
string Bulk_quote::debug() const
{
ostringstream str("");
str<<Quote::debug() << "threshold:" <<min_qty<<",Discount"<<discount;
return str.str();
}
string Over_part_original_price::debug() const
{
ostringstream str("");
str<<Quote::debug()<< "threshodle" << this->over_threshould << ",Discount" << discount;
return str.str();
}
15.12
有必要,如15.11的两个派生类的debug函数所示,二者并不冲突,派生类可以重写基类的函数,但是也可以指定此后不能再重写。
15.13
derived中的print函数中调用了print,但是调用的是自己定义的print,这也会导致递归,如果想要调用基类的print,需要使用作用域运算符来访问。
15.4
a。基类
b。基类
c。基类
d。派生类
e。基类
f。派生类
15.4 抽象基类
如果某一个类仅用于制作接口,实例化它的对象没有任何意义,我们可以通过为其函数添加添加纯虚函数来实现。
纯虚函数就是在声明一个虚函数时,在形参列表后面=0;
我们一般不会去定义一个纯虚函数,但是编译器允许我们这也做,前提是必须在类外进行定义。
virtual double net_price(size_t size)const=0;
//可以定义,但是必须在类外,但是一般不会定义
double Disc_quote::net_price(size_t size) const
{
return 0.0;
}
包含了纯虚函数的类被成为抽象类,抽象类不可以创建对象。
练习
15.15,15.16
class Disc_quote:public Quote
{
public:
Disc_quote()=default;
Disc_quote(const string& book, double price, size_t qty, double disc) :Quote(book,price),discount_threshold(qty),discount(disc){};
virtual double net_price(size_t size)const=0;
protected:
size_t discount_threshold;
double discount;
private:
};
class Bulk_quote :
public Disc_quote
{
public:
Bulk_quote() = default;
~Bulk_quote() = default;
Bulk_quote(const string& s, double p, size_t q, double dis);
double net_price(std::size_t n) const override;
virtual string debug() const override final;
};
class Over_part_original_price :public Disc_quote {
public:
Over_part_original_price(const string&s, double p, size_t q, double dis);
double net_price(std::size_t n) const override;
virtual string debug() const override final;
};
cpp文件
#include "pch.h"
#include "Bulk_quote.h"
#include <iostream>
#include<sstream>
Bulk_quote::Bulk_quote(const string & s, double p, size_t q, double dis):Disc_quote(s,p,q,dis)
{
}
double Bulk_quote::net_price(std::size_t n) const
{
std::cout << "Bulk_quote::net_price" <<std::endl;
double money=0.0;
if (n>= discount_threshold)
{
money = price * n*discount;
}
else {
money = n * price;
}
return money;
}
string Bulk_quote::debug() const
{
ostringstream str("");
str<<Quote::debug() << "threshold:" <<discount_threshold<<",Discount"<<discount;
return str.str();
}
Over_part_original_price::Over_part_original_price(const string & s, double p, size_t q, double dis):Disc_quote(s,p,q,dis)
{
}
double Over_part_original_price::net_price(std::size_t n) const
{
std::cout << "Over_part_original_price::net_price(std::size_t n) " << std::endl;
double money = 0.0;
if (n<=discount_threshold)
{
money = n * price*discount;
}
else {
money = (n - discount_threshold)*price + discount_threshold * price*discount;
}
return money;
}
string Over_part_original_price::debug() const
{
ostringstream str("");
str<<Quote::debug()<< "threshodle" << this->discount_threshold << ",Discount" << discount;
return str.str();
}
15.17
报错,不允许使用抽象类的对象