【问题标题】:C++ polymorphism and default argumentC++ 多态性和默认参数
【发布时间】:2011-03-11 12:56:44
【问题描述】:

我有这些课程:

class Base
{
    public:
        virtual void foo(int x = 0)
        {
            printf("X = %d", x);
        }
};

class Derived : public Base
{
    public:
        virtual void foo(int x = 1)
        {
            printf("X = %d", x);
        }
};

当我有:

Base* bar = new Derived();
bar->foo();

我的输出是“X = 0”,即使 foo 是从 Derived 调用的,但是当我有时:

Derived* bar = new Derived();
bar->foo();

我的输出是“X = 1”。这种行为正确吗? (从声明类型中选择默认参数值,而不是从实际对象类型中选择它)。这会破坏 C++ 多态性吗?

如果有人在没有指定实际函数参数的情况下使用虚函数并使用函数的默认参数,则会导致很多问题。

【问题讨论】:

  • 在 printf() 中添加一些内容,它实际上会告诉您正在调用哪个函数
  • 很明显被调用的函数是Derived::foo
  • 怎么样?他们都打印类似“X = value”的东西。您不能使用该值来确定正在调用哪个值。尝试在 base 中打印“Base: X = %d”,您将能够分辨出调用的是哪一个。

标签: c++


【解决方案1】:

即使你重写了一个函数,默认参数也会被保留!而且这种行为是正确的。让我从 C++ 标准中搜索参考。

C++ 标准中的第 8.3.6/10 节 [默认参数] 说,

虚函数调用 (10.3) 使用 中的默认参数 虚函数声明 由静态类型决定 指针或引用表示 对象一个覆盖函数 派生类不获取默认值 来自函数的参数 it 覆盖

标准本身的例子

struct A {
     virtual void f(int a = 7);
};
struct B : public A {
     void f(int a);
};
void m()
{
    B* pb = new B;
    A* pa = pb;
    pa->f(); //OK, calls pa->B::f(7)
    pb->f(); //error: wrong number of arguments for B::f()
}

此外,不仅保留它,而且每次调用函数时都会对其进行评估:

§8.3.6/9 说,

每个默认参数都被评估 函数被调用的时间

【讨论】:

  • @Nawaz:从另一个答案复制/粘贴而不是链接到它并不能真正帮助整体。尤其是当其他人已经提供了链接时。
  • @Jon:复制粘贴哪个答案?你的意思是我从另一个答案复制粘贴?哪个答案?
  • @Jon:好的。我现在说你的答案。但是,如果您认为它回答了问题,那么您应该说它重复主题并投票关闭它!
  • @Nawaz:如果你仔细阅读这些问题,你会发现它们不是同一个问题。另外,你不认为报复性投票是不成熟的吗?
  • @Nawaz:我从没想过要隐瞒事实;我还解释了我的反对意见。另外,刚刚我的反对票消失了,这难道不奇怪吗?啊,巧合……无论如何,祝你有美好的一天。
【解决方案2】:

行为是正确的。查看此问题的答案以获得解释:

Can virtual functions have default parameters?

道德:将默认参数值视为函数签名的一部分,在覆盖虚函数时不要修改它们

【讨论】:

  • @Jon,谢谢你的链接,原来的答案肯定会得到我的支持......
  • @Jon:如果你认为这个链接回答了这个问题,那么你应该投票关闭这个话题,因为它可能重复!
  • @Nawaz:正如我已经说过的:该问题的答案也回答了这个问题。问题本身相同。
  • @Jon:但是您提供了链接作为对这个问题的回答。根据你的说法,他还问什么他不知道阅读链接?
  • 我认为道德是避免使用默认参数。它们降低了代码的可读性。
【解决方案3】:

我认为这就是 C++ 设计的。

多态是由虚表完成的,虚表内部玩的是函数指针,但参数的默认值并没有和函数指针一起存储,是在编译阶段绑定的,所以只能先看默认值在它的类型中,在你的第一种情况下,它是 Base,然后它使用 0 作为默认值。

【讨论】:

  • 这在技术上是正确的,但作为答案具有误导性,因为 C++ 标准没有强制要求 vtables 实现多态性。它具体说明了在这种情况下应该发生什么;如果它将未定义作为实现细节,那么任何人都可以编写一个符合标准的编译器,该编译器使用像 vtable 这样的机制来绑定默认值。
  • 是的。但是对于那些从事标准工作的人,他们也会考虑该功能是否实用。我只是认为它是这样设计的,因为另一种方式不实用。任何函数都可以采用许多参数,所有参数都可以具有默认值。这使得运行时绑定成为不可能的任务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-01
  • 1970-01-01
相关资源
最近更新 更多