继承——虚函数

简介: 继承——虚函数

虚函数的定义

在基类与派生类那里我们介绍了当我们使用基类的引用或指针调用一个虚成员函数的时候会执行动态绑定,因为我们在运行之前也并不知道会调用哪个版本的虚函数,因为我们只有在运行的时候才能确定我们将会调用哪一个版本的虚函数,所以我们在定义的时候必须给每一个虚函数提供定义。

对函数的调用在运行时才被解析

#include<iostream>
using namespace std;
class Quote
{
public:
    string book_ISBN;//书的编号
    double price;
    Quote(const string& name,double p,string No):book_name(name),price(p),book_ISBN(No)
    {
    }
    virtual double net_price(size_t n) const
    {
        return n*price;
    }
    virtual string get_ISBN() const
    {
        return book_ISBN;
    }
    Quote(double p,string No):price(p),book_ISBN(No)
    {}
    virtual ~Quote()=default;
private:
    string book_name;
};
class Bulk_Quote:public Quote
{
private:
    size_t min_qry;
    double discount;
    string book_name;
public:
    Bulk_Quote(const string& name,string book_ISBN,double price,size_t qry,double dis):Quote(price,book_ISBN),book_name(name),min_qry(qry),discount(dis)
    {}
    double net_price(size_t n) 
    {
        if(n>=min_qry)
        price=price*discount;
        return n*price*discount;
    }
    string get_ISBN() const
    {
        return book_ISBN;
    }
    ~Bulk_Quote()
    {}
};
void Total_price(ostream& os,const Quote& item,size_t n)
{
    double ret=item.net_price(n);
    os<<"ISBN:   "<<item.get_ISBN()<<endl;
    os<<"net_price:   "<<ret<<endl;
}
int main()
{
    Quote base("fengxu",10.78,"0-201-82470a-1");
    Bulk_Quote derived("fengxu","0-201-82470a-1",10.78,10,0.7);
    Total_price(cout,derived,40);
    Total_price(cout,base,10);
    return 0;
}

如上代码所示,虽然我们指定的类型时Quote的引用,但是当我们传进derived时,item会绑定在Bulk_Quote类型的对象上,这时调用则是Bulk_Quote::net_price,而传入base时,则是与Qutoe绑定,此时调用的则是Quote::net_price.

final和override关键词

在我们定义派生类的时候,有时候我们如果在派生类里面定义了一个名字和虚函数相同但是形参列表顺序不同的函数,在编译器看来这么写其实是合法的,但是这个函数和虚函数没有任何关系,这也意味着我们原先需要覆盖的虚函数并没有被覆盖,就实际要求来看这时候发生了错误。

这时候就要拿出我们的override关键词了,当我们用override标记了这个函数,如果这个函数并没有成功覆盖已经存在的虚函数,此时编译器就会报错:

class Quote
{
public:
    Quote() =default;
    Quote(double size_price,const string& number):size_price(size_price),m_number(number) 
    {
    }
    string IseN()
    {
        return m_number;
    }
    virtual double Total_price(double size_price,int n)
    {
        return n*size_price;
    }
    virtual ~Quote() =default;
    private:
    string m_number;
    protected:
    double size_price=0.0;
};   
class Bulk_Qutoe:public Quote
{
public:
    Bulk_Qutoe()=default;
    Bulk_Qutoe(double,const string&,int,double);
    double Total_price(int book_number,double size_price)  const override;
private:
    double discount;
    int book_number;
    string book_name;
};
class Bulk_Qutoe:public Quote
{
public:
    Bulk_Qutoe()=default;
    Bulk_Qutoe(double,const string&,int,double);
    double Total_price(int book_number,double size_price)  const ;
private:
    double discount;
    int book_number;
    string book_name;
};

对于上述Bulk_Quote的俩种不同写法,前者会报错,而后者则是合法的,充分的说明了override的作用。

final关键词的作用则是当我们把某个函数标记为final后,之后所有试图覆盖该函数的操作都是非法的。·

虚函数和默认实参

和其他函数一样,虚函数也有默认实参,如果调用了默认实参。则实参值由本次调用的静态类型决定。

通俗一点来说,当我们使用基类的引用或者指针来调用函数的时候,此时使用的是基类的默认实参,哪怕当前使用的是派生类里面的函数也是这样,此时传进去的仍然是基类函数定义的默认实参,如果派生类重新定义使该函数被覆盖,此时用派生类的引用或者指针对函数进行调用,传递进去的就是派生类定义的默认实参。

回避虚函数的机制

在一些特定的场景下,我们希望对虚函数的调用不要进行动态绑定,而是我们可以自行决定我们使用虚函数的某一个特定的版本,这时候我们可以使用作用域运算符来实现执行虚函数的某一个特定版本,实例代码如下:

double undiscounted=basep->Quote::net_price(42);

这里baseP是一个指向基类的指针。

虚函数的回避机制常常用于派生类已经被覆盖的虚函数需要调用其基类版本,如果不使用回避机制会造成函数的无限递归。

相关文章
|
7月前
|
C++
C++一分钟之-虚函数与抽象类
【6月更文挑战第21天】在C++中,虚函数与抽象类是多态的基础,增进类间耦合与灵活性。虚函数实现动态绑定,抽象类定义不可实例化的接口。关键点包括:记得使用`virtual`,避免滥用虚函数,确保派生类实现纯虚函数。抽象类不能直接实例化,派生类必须实现所有纯虚函数。通过实例代码学习和实践,能更好地掌握这些概念以优化代码设计。
62 2
|
C++
38.【C++ 虚函数 纯虚函数 虚基类 (最全详解)】(一)
38.【C++ 虚函数 纯虚函数 虚基类 (最全详解)】
69 0
|
C++
38.【C++ 虚函数 纯虚函数 虚基类 (最全详解)】(二)
38.【C++ 虚函数 纯虚函数 虚基类 (最全详解)】
137 0
|
5月前
|
编译器 C++
C++的基类和派生类构造函数
基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承。构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类的构造函数,当然更不能成为普通的成员函数。 在设计派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数完成,但是大部分基类都有 private 属性的成员变量,它们在派生类中无法访问,更不能使用派生类的构造函数来初始化。 这种矛盾在C++继承中是普遍存在的,解决这个问题的思路是:在派生类的构造函数中调用基类的构造函数。 下面的例子展示了如何在派生类的构造函数中调用基类的构造函数:
|
7月前
|
数据安全/隐私保护
继承——基类与派生类
继承——基类与派生类
|
8月前
|
C++ 编译器 存储
|
存储 编译器 C++
<c++>虚函数与多态 | 虚函数与纯虚函数 | 多态的实现原理 | 虚析构函数
<c++>虚函数与多态 | 虚函数与纯虚函数 | 多态的实现原理 | 虚析构函数
153 0
|
C++
基类派生类多态虚函数?
通常在层次关系的根部有一个基类,其他类则直接或间接的从基类继承而来,这些继承得到的类称为派生类。基类负责定义在层次关系中所有类共同拥有的成员,而每个派生类定义各自特有的成员。
121 0
<c++> 类的继承 | 基类与派生类 | 构造函数与析构函数
<c++> 类的继承 | 基类与派生类 | 构造函数与析构函数
165 0
|
编译器 定位技术
在父类的构造函数中调用虚函数为什么不能实现多态
在父类的构造函数中调用虚函数为什么不能实现多态
117 0