我创建了一个抽象基类,它有一个带有默认参数的纯虚方法。
class Base {
...
virtual someMethod(const SomeStruct& t = 0) = 0;
...
}
class Derived : public Base {
...
virtual someMethod(const SomeStruct& t = 0);
...
}
所以我想知道将默认参数设置为纯虚拟和整体虚拟方法是一个好习惯吗?
答案 0 :(得分:33)
实际上,您的代码是默认参数最糟糕的使用模式之一,因为它涉及继承和多态行为。我支持建议,看看相关的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)
答案 1 :(得分:14)
我经常希望同时使用默认参数和虚拟功能。其他人正确地指出,这会导致模棱两可,通常不是一个好主意。有一个相当简单的解决方案,我使用的解决方案。为虚拟函数指定一个不同的名称,使其受到保护,然后使用默认参数提供一个公共函数来调用它。
class Base {
protected:
virtual void vSomeMethod(const SomeStruct& t ) = 0;
public:
void someMethod( const SomeStruc& t = 0 )
{ vSomeMethod( t ); }
}
派生类只是覆盖vSomeMethod
,并且根本不担心默认参数。
答案 2 :(得分:6)
如果可能,请不要使用默认参数,但如果这样做,请勿重新定义它们(see the text for details)
购买Scott Meyers的Effective C ++书籍。你不会后悔的。
答案 3 :(得分:0)
我会:
这样派生类根本不必关心默认值。
答案 4 :(得分:0)
如果您希望此代码有意义:
Base* p = new Derived;
p->someMethod();
因为p
的静态类型是Base*
,所以它是在调用时使用的Base签名。
分配默认值,并且作为虚拟功能,呼叫将重定向到Derived。
如果您希望Derived :: someMethod从Base*
而不是Derived*
获得不同的值,您甚至可以以不同的方式定义它们。
重要的是记录这些“关系”,因为大多数程序员不会从简单的代码阅读中理解它们。
当然,如果所有这些都不适合您的特定情况,产生比其他情况更多的混淆,请避免虚函数上的默认参数,并使用辅助非虚拟函数来正确调用它们。
但同样考虑到 - 通过读者观点 - 默认参数比过度函数更具有解释性,私有地调用另一个具有不可读参数返工的函数。