7

有人可以解释为什么下面代码的结果是 "class 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;
}
4

3 回答 3

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;
}

我们观察到以下输出:

class B::1
class B::2

ideone行动。

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


技术上的解释是有两种处理默认参数的方法:

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

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

于 2012-06-03T15:25:56.703 回答
5

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

于 2012-06-03T15:10:56.060 回答
5

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

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

于 2012-06-03T15:13:24.850 回答