先来看这样一段代码

class Base
{
public:
    virtual void print(int a = 1) const
    {
        std::cout << "Base " << a << "\n";
    }
};

class Derived : public Base
{
public:
    virtual void print(int a = 2) const override
    {
        std::cout << "Derived " << a << "\n";
    }
};

请问:若按如下方式调用,会输出什么?

Base *p = new Derived();
p->print();

答案:输出 Derived 1(而非 Base 1Derived 2)。

原因:

  • 虚函数动态绑定,在运行时根据对象的实际类型决定调用哪个函数,因此这里调用的函数为 Base::print
  • 默认实参静态绑定,在编译期根据指针的声明类型决定默认实参的值,因此这里的 p->print() 相当于 p->print(1)

因此,重写基类函数时不要重新定义函数的默认参数,以避免出现上文中的坑。

参考资料:

  1. Effective C++ item 37: Never Redefine a Function's Inherited Default Parameter Value
  2. 默认实参 - cppreference.com