15.3虚函数 15.4抽象基类 15.5访问控制与继承

 #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);

猜你喜欢

转载自www.cnblogs.com/Congliang0229/p/11884765.html