31

我创建了一个抽象基类,它有一个带有默认参数的纯虚方法。

class Base {
    ...
    virtual someMethod(const SomeStruct& t = 0) = 0;
    ...
}

class Derived : public Base {
    ...
    virtual someMethod(const SomeStruct& t = 0);
    ...
}

所以我想知道将默认参数设置为纯虚拟和整体设置为虚拟方法是一种好习惯吗?

4

5 回答 5

39

实际上,您的代码是默认参数最糟糕的使用模式之一,因为它涉及继承和多态行为。我支持查看相关的 Scott Meyers 提示的建议,但这里有一个简短的概述:

在多态调用的情况下,根据静态类型的声明使用默认参数,而不是动态类型。这是合乎逻辑的,因为运行时不知道默认参数,但打破了关于多态行为的任何合理假设。例如,

#include <cstdio>

class Base
{
        public:
                virtual void f(int a = 1)
                {
                        printf("Base::f(%d)\n", a);
                }
};

class Deriv : public Base
{
        public:
                virtual void f(int a = 2)
                {
                        printf("Deriv::f(%d)\n", a);
                }
};

int main()
{
        Base* a = new Deriv();
        a->f();
        delete a;
        return 0;
}

产量:

Deriv::f(1)
于 2012-08-27T10:18:56.813 回答
22

我经常希望像你一样使用默认参数和虚函数。然而,其他人正确地指出,这会导致模棱两可,通常不是一个好主意。有一个相当简单的解决方案,我使用的一个。给你的虚函数一个不同的名字,让它受到保护,然后提供一个带有默认参数的公共函数来调用它。

class Base {
protected:
    virtual void vSomeMethod(const SomeStruct& t ) = 0;
public:
    void someMethod( const SomeStruc& t = 0 )
    { vSomeMethod( t ); }
}

派生类只是覆盖vSomeMethod并且根本不用担心默认参数。

于 2012-08-27T10:24:34.353 回答
6

尽可能不要使用默认参数,但如果你这样做了,永远不要重新定义它们(详见正文

购买 Scott Meyers 的两本 Effective C++ 书籍。你不会后悔的。

于 2012-08-27T10:03:08.360 回答
0

我会:

  • 用参数定义虚函数(无默认值)
  • 在基类中定义非虚函数,根本没有参数,调用传递正确默认参数的虚函数

这样,派生类根本不必关心默认值。

于 2012-08-27T10:26:31.520 回答
0

如果您希望此代码有意义:

Base* p = new Derived;
p->someMethod();

因为它的静态类型pBase*调用时使用的 Base 签名。分配了默认值,并且作为虚拟函数,调用被重定向到 Derived。

如果您希望 Derived::someMethod 从而Base*不是Derived*...接收不同的值,您甚至可以对它们进行不同的定义

重要的是要很好地记录这些“关系”,因为大多数程序员不会通过简单的代码阅读来理解它们。

当然,如果所有这些都不适合您的特定上下文,会产生更多的混乱,请避免虚拟函数的默认参数,并使用辅助非虚拟函数来正确调用它们。

但还要考虑到——从读者的角度来看——一个默认参数比一个重载函数私下调用另一个具有不可读参数返工的重载函数更明确。

于 2012-08-27T11:35:51.523 回答