#include <iostream> using namespace std; class Quote{ public: Quote() = default; Quote(const std::string &book, double sales_price): bookNo(book),price(sales_price){}; string isbn() const{ return bookNo;}; virtual double net_price(size_t 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& book, double p, size_t qty, double disc):Quote(book,p),min_qty(qty), discount(disc){}; double net_price(size_t) const override ; private: size_t min_qty = 0; double discount = 0.0; }; double Bulk_quote::net_price(size_t cnt) const { if(cnt >= min_qty){ return cnt*(1 - discount) * price; } else return cnt * price; } double print_total(ostream& os, const Quote& item, size_t n){ //根据传入item形参时的对象类型调用Quote::net_price //或者Bulk_quote::net_price double ret = item.net_price(n); os << "ISBN: " << item.isbn() << "# sold:" << n << "total due:" << ret << endl; return ret; } int main(){ Quote base("0-201-82470-1",50); print_total(cout, base, 10); //调用基类的net_price Bulk_quote derived("0-201-82470-1",50,5,.19); print_total(cout, derived, 10); //调用派生类的net_price }
15.3 虚函数
1、通常情况下,我们可以不为不使用的某个函数提供定义。但是我们必须为每一个虚函数都提供定义,而不管它是否被用到了,这是因为编译器野无法确定到底会使用哪个虚函数。
2、动态绑定只有在我们通过指针或引用调用虚函数时才会发生。当我们通过一个具有普通类型的表达式调用虚函数时,咋编译时就会将调用的版本确定下来:
base = derived; //把derived的Quote部分拷贝给base; base.net_price(20); //调用Quote::net_price
3、基类中的虚函数在派生类中隐含地也是一个虚函数,用不用virtual关键字都可以。但派生类中的虚函数形参和返回类型必须与基类严格匹配,否则它将只是一个普通重载。
4、可以用override关键字来说明派生类中的虚函数,并将它与重载区分开。如果它的形参和返回值有误,编译器还会报错。
void f1(int) const override;
override只能用给虚函数。
5、还可以将某个函数声明为final,表示它不可以被覆盖。
void f1(int) const final;
6、虚函数也可以有默认实参,实参值由本次调用的静态类型决定。
换句话说,如果我们通过基类的引用或指针调用函数,则使用基类中定义的默认实参,就算他运行的是派生类中的函数版本。这时候传入派生类函数的时基类函数定义的默认实参。
tips:如果虚函数使用默认实参,则基类和派生类中定义的默认实参最好一致。
7、回避虚函数的机制:
如果想强迫执行虚函数的某个特定版本,可以使用作用域运算符:
//强行调用基类中定义的函数版本而不管baseP的动态类型是什么 double undiscounted = baseP->Quote::net_price(42);
原文:https://www.cnblogs.com/Congliang0229/p/11884765.html