玩命加载中 . . .

15.3-虚函数


虚函数

动态绑定只有通过指针或引用调用虚函数时才会发生

一旦某个函数被声明为虚函数,则在所有派生类中它都是虚函数

一个派生类的函数如果覆盖了某个继承而来的虚函数,则它的形参类型必须与它覆盖的基类函数完全一致

派生类中虚函数的返回类型也必须与基类函数匹配,有一个例外,『当类的虚函数返回类型是类本身的指针或引用时,上述规则无效』

final和override说明符

只有虚函数才能被覆盖,可以使用override关键字来说明派生类中的虚函数

struct B {
    virtual void f1(int) const;
    virtual void f2();
    void f3();
};
struct D1 : B {
    void f1(int) const override;    // 正确,f1与基类的f1匹配
    void f2(int) override;  // Err,B没有形如f2(int)的函数
    void f3() override; // Err,f3不是虚函数
    void f4() override; // Err,B没有名为f4的函数
};

可以把某个函数指定为final,则之后任何尝试覆盖该函数的操作都将引发错误

struct D2 : B {
    void f1(int) const final;   // 不允许后续的其他类覆盖f1(int)
};
struct D3 : D2 {
    void f1(int) const; // Err,D2已将f1声明成final
};

如果虚函数使用默认实参,则基类和派生类中定义的默认实参最好一致

回避虚函数的机制

强制调用基类的版本

// 强行调用基类中定义的函数版本而不管baseP的动态类型是什么
double undiscounted = baseP->Quote::net_price(42);

如果一个派生类虚函数需要调用它的基类版本,但是没有使用作用域运算符,则在运行时该调用将被解析为对派生类版自身的调用,从而导致无限递归

抽象基类

在声明语句中的分号之前书写=0,可以定义为纯虚函数

class Disc_quote : public Quote {
public:
    Disc_quote() = default;
    Disc_quote(const string& book, double price, size_t qty, double disc):
    Quote(book, price), quantity(qty), discount(disc) {}
    double net_price(size_t) const = 0;
protected:
    size_t quantity = 0;    // 折扣使用的购买量
    double discount = 0;    // 折扣
};

可以为纯虚函数提供定义,但必须定义在类的外部

含有(或未经覆盖直接继承)纯虚函数的类是抽象基类

// Disc_quote声明了纯虚函数,而Bulk_quote将覆盖该函数
Disc_quote discounted;  // Err,不能创建抽象基类的对象
Bulk_quote bulk;    // Yes

派生类构造函数只初始化它的直接基类Bulk_quote只需要调用它的直接基类Disc_quote的构造函数就可以了

class Bulk_quote : public Disc_quote {
public:
    Bulk_quote() = default;
    Bulk_quote(const string& book, double price, size_t qty, double dissc):
        Disc_quote(book, price, qty, disc) {}
    double net_price(size_t) const override;
};

文章作者: kunpeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kunpeng !
  目录