虚函数查找的规则是啥?

Posted

技术标签:

【中文标题】虚函数查找的规则是啥?【英文标题】:What are the rules for virtual function lookup?虚函数查找的规则是什么? 【发布时间】:2011-03-21 00:29:18 【问题描述】:
#include <iostream>
class base

    public:
    virtual void print (int a)
       
        std::cout << "a: " << a << " base\n";
       
    virtual void print (int a, int b)
       
        std::cout << "base\n";
       
;

class derived : public base

    public:
    virtual void print (double d)
       
        std::cout << "derived\n";
       
;

int main ()

    int i = 10; 
    double d = 10000.0;
    base *b = new derived (); 
    b->print (i, i); 
    b->print (d);

    return 0;

这个函数的输出是:

base
a: 10000 base
为什么b-&gt;print (d) 不调用派生类实现和 对'd' 执行静态转换以提供与基类的匹配 实施? 在查找虚函数时这里应用了什么规则?

【问题讨论】:

您使用的是基础类型,而不是派生类型。它没有接受双精度的函数,因此它强制转换为 int 以找到最佳匹配。 【参考方案1】:

derived::print 不会覆盖base 中的任何成员函数。它被声明为具有double 类型的单个参数,但base 中名为print 的两个虚成员函数被声明为具有int 类型的一个和两个参数。

当您使用b-&gt;print(d) 时,在重载解析期间仅考虑base 中的成员函数,因此仅考虑void base::print(int)void base::print(int, int)。找不到void derived::print(double),因为编译器不知道b 指向derived 对象。

如果derived 要覆盖base 中声明为虚拟成员函数的两个print 函数之一,则将在运行时调用该覆盖。

(在一些相关的注释中,derived::print 隐藏了两个base::print 成员函数,因此如果您尝试使用基类print 函数之一,例如derived().print(1, 1),它将失败。您需要使用 using 声明来使这些成员函数在名称查找期间可用。)

【讨论】:

【参考方案2】:

重载解析发生在编译时。覆盖发生在运行时。

因此,b-&gt;print(d); 的重载决议首先发生。这选择了Base::print(int),因为它是唯一的一个参数print

在运行时,b 指向一个没有覆盖 Base::print(int)Derived 对象。因此,Base::print(int) 仍然被调用。

【讨论】:

【参考方案3】:

因为 double 可以在它看到的第一个定义中(在基类中)自动转换为 int

explicit关键字或this question

【讨论】:

以上是关于虚函数查找的规则是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在c++中虚函数和多态性是啥意思

在某些派生类中实现虚函数的正确方法是啥?

使用通用虚函数实现的任意组合实现派生类的正确方法是啥?

虚函数以及纯虚函数

继承与多态C++:继承中的赋值兼容规则,子类的成员函数,虚函数(重写),多态

17. 虚析构函数再谈动态绑定多态到底是啥抽象类