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

时间:2012-06-03 15:07:01

标签: 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;
}

3 个答案:

答案 0 :(得分:6)

因为默认参数是根据this的静态类型解析的(即变量本身的类型,如A&中的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;
}

我们观察到以下输出:

class B::1
class B::2

ideone的行动。

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


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

  • 创建一个新功能以充当蹦床:void A::func() { func(1); }
  • 在呼叫网站a.func() =&gt;添加缺少的参数a.func(/*magic*/1)

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

答案 1 :(得分:5)

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

答案 2 :(得分:5)

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

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