虚拟方法与标准默认参数

Virtual methods versus standard default argument

本文关键字:默认 参数 标准 方法 虚拟      更新时间:2023-10-16

想象以下场景

class B
{
public:
    int n;
    B() { n = 1;};
    virtual int shift() const { return n; }
};
class D : public B
{
public:
    D() { n = 2;};
    int shift() const { return n; }
};
int main()
{
    D d;
    std::cout << d.shift() << std::endl;
    B *b = &d;
    std::cout << b->shift() << std::endl;
    std::cin.get();
    return 0;
}

的输出非常清楚:2和2由于虚和向下转换(从基到子)。

但是,在代码中做一些更改,如:

class B
{
public:
    //int n;
    //B() { n = 1;};
    virtual int shift(int n = 1) const { return n; }
};
class D : public B
{
public:
    //D() { n = 2;};
    int shift(int n = 2) const { return n; }
};

并保持相同的main(),我们将输出:2和1。如果方法是虚拟的,为什么是"1" ?

多谢!

在此语句中

std::cout << b->shift() << std::endl;

编译器根据指针b的静态类型使用类B中函数的声明,并使用相应的默认实参。

编译器首先计算函数的实参这个实参是声明

中的默认实参
virtual int shift(int n = 1) const { return n; }

,然后使用动态绑定,从D类调用函数:)

试试下面的例子

#include <iostream>
int main()
{
struct B
{
    virtual ~B() = default;
    virtual int shift(int n = 1) const { std::cout << "B::shift( int ): "; return n; }
};
struct D : B
{
    virtual int shift(int n = 2) const { std::cout << "D::shift( int ) : "; return n; }
};
    D d;
    B *b = &d;
    std::cout << b->shift() << std::endl;
}    

得到

D::shift( int ) : 1
^^^               ^^^ 

即编译器根据指针b的静态类型在类B的作用域内查找名称shift。但是使用动态绑定机制从类D调用函数。

显然,编译器在修改函数名时使用了默认参数值。

上面评论中的重复给出了另一个原因。编译器在编译时解析默认参数。