虚函数默认参数和重载

时间:2014-08-05 19:00:59

标签: c++ overloading virtual default-parameters

这个问题涉及这些问题中讨论的常见问题:

Can virtual functions have default parameters?

Virtual functions default parameters

以下是c ++当前在虚拟函数中使用默认参数的内容:

struct Base
{
    virtual void foo(int one = 1, int two = 2)
            { cout << "one: " << one << " two: " << two << endl; }
};

struct Derived : public Base
{
    virtual void foo(int one = 3, int two = 4) 
        { Base::foo(one, two); cout << " derived!" << endl; }
};

int main()
{
    Base* b = new Base();
    Base* d = new Derived();

    Derived* dp = new Derived();

   b->foo();
   d->foo();
   dp->foo();

   return 0;
}

输出:

one: 1 two: 2
one: 1 two: 2
 derived!
one: 3 two: 4
 derived!

这是我希望在c ++虚函数默认参数中存在的行为:

#include <iostream>

using namespace std;

struct Base
{
    virtual void foo () { foo(1, 2); }
    virtual void foo (int one) { foo(one, 2); }
    virtual void foo(int one, int two)
            { cout << "one: " << one << " two: " << two << endl; }
};

struct Derived : public Base
{   
    virtual void foo() { foo(3, 4); }
    virtual void foo(int one, int two) 
        { Base::foo(one, two); cout << " derived!" << endl; }
};

int main()
{
    Base* b = new Base();
    Base* d = new Derived();

    Derived* dp = new Derived();

   b->foo();
   d->foo();
   dp->foo();

   return 0;
}

输出:

one: 1 two: 2
one: 3 two: 4
 derived!
one: 3 two: 4
 derived!

所以,基本上,如果我想覆盖父类中的默认参数,我将只创建一个具有该数量参数的新foo。请注意,派生会覆盖no-arg条件,但不会覆盖one-arg条件。 作为旁注,我当前的项目使用纯虚基类。我经常有基类类型和派生类类型的指针。我希望从任一指针调用具有相同的结果。

问题:

我已经阅读了很多与此主题相关的问题,但它们似乎都没有提供合理的解决方案。大多数解决方案都会在整个项目中产生更加丑陋的代码。

有些人说“不要在虚函数上使用默认参数”,但是我需要在我调用函数的每个地方都设置默认值。似乎最好只是发表评论,说“也改变基类”和“也改变派生类”,而不是必须改变调用函数的所有地方。

有人说只在基类中有默认参数,但这意味着在使用默认值之前,需要将任何指向派生对象的指针强制转换回基指针。这也使很多代码变得丑陋。

我有理由避免上述设计吗?

3 个答案:

答案 0 :(得分:3)

在某些时候,如果您根据他们称之为foo的静态类型更改默认值,您的代码的未来维护者将会感到困惑,困惑和/或感到困惑,所以我要去假设你不关心。

鉴于您关注的是有人更改了父级中的默认值而忘记更新使用非虚拟接口模式轻松解决的子类:

#include <iostream>

using namespace std;

struct Base
{
    void foo(int one = 1, int two = 2) { foo_impl(one, two); }

protected:
    virtual void foo_impl(int one, int two)
    { cout << "one: " << one << " two: " << two << endl; }
};

struct Derived : public Base
{   
protected:
    virtual void foo_impl(int one, int two)
    { Base::foo_impl(one, two); cout << " derived!" << endl; }
};

int main()
{
    Base* b = new Base();
    Base* d = new Derived();

    Derived* dp = new Derived();

    b->foo();
    d->foo();
    dp->foo();

    return 0;
}

答案 1 :(得分:3)

我认为问题在于理解发生了什么&#34;是函数参数的默认值是在编译时解析的 - 这意味着除非它非常明显和简单,否则编译器不会知道某个指针所指向的类,并且不会给出正确的论点。换句话说,在确定函数的参数时,编译器将使用指针的类。绝对没有办法解决这个问题(除了#34;知道你要使用哪个类&#34;,然后它使用虚函数毫无意义)。

解决方案取决于你真正想要做的事情,但一个明显的答案是不使用默认参数。另一种解决方案就像你一样,是某种间接函数调用,其中&#34;没有参数&#34;函数不同于一个和两个参数函数。

但是,首先想知道你的设计是否正确也许是一个好主意。也许你需要在某个地方找到一个不同的解决方案......

答案 2 :(得分:0)

首先,您未在示例中使用默认参数。因此,通常的默认参数不适用于您的代码的问题。在您的代码中,子类可以覆盖默认参数,无论通过Derived还是Base指针使用Derived,都可以按预期工作。因此,我认为你的方法没有问题,对我来说似乎很好。