代码执行派生类方法,但从基类方法获取默认参数

Are*_*yst 7 c++ virtual derived default-parameters

有人可以解释为什么下面的代码的结果将是"B类:: 1"?

为什么派生类的虚方法使用基类的默认参数而不是自己的默认参数?对我来说这很奇怪.提前致谢!

码:

#include <iostream>

using namespace std;

class A
{
public:
    virtual void func(int a = 1)
    {
        cout << "class A::" << a;
    }
};

class B : public A
{
public:
    virtual void func(int a = 2)
    {
        cout << "class B::" << a;
    }
};

int main()
{
    A * a = new B;
    a->func();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Mat*_* M. 6

因为默认参数是根据静态类型this(即变量本身的类型,如A&in A& a;)解析的.

稍微修改您的示例:

#include <iostream>

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

class B : public A
{
public:
    virtual void func(int a = 2)
    {
        std::cout << "class B::" << a << "\n";
    }
};

void func(A& a) { a.func(); }

int main()
{
    B b;
    func(b);
    b.func();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我们观察到以下输出:

class B::1
class B::2
Run Code Online (Sandbox Code Playgroud)

ideone行动.

由于这个原因,不建议虚函数更改默认值.不幸的是,我不知道任何编译器警告这个结构.


技术说明是有两种处理默认参数的方法:

  • 创建一个新的功能来充当蹦床: void A::func() { func(1); }
  • 在调用站点加入缺少的参数a.func()=>a.func(/*magic*/1)

如果它是前者(假设A::func声明virtual也是如此),那么它会像你期望的那样工作.然而,后一种形式是选举产生的,要么是因为virtual当时没有预见到问题,要么因为它们被认为是无关紧要的(如果有的话......).


Rub*_*ben 5

因为默认值在编译期间被替换并且取自声明,而在运行时确定要调用的实函数(A :: func或B :: func).


thb*_*thb 5

因为C++中的多态性在运行时生效,而默认参数的替换在编译时生效.在编译时,编译器不知道(并且不应该知道)指针所a指向的对象的动态类型.因此,它采用它所知道的唯一类型的默认参数a,在您的示例中是A *.

(顺便提一下,这也是接口/头部而不是实现/定义中给出默认参数的原因.编译器从不在实现的机器代码中插入默认参数,而只在调用者的机器代码中插入.技术上,默认参数是调用者的属性;调用者不知道 - 也不应该知道 - 对象的动态类型.)