2

我有一个现有的方法(或一般的函数),我需要增加额外的功能,但我不想在代码的其他地方破坏该方法的任何使用。例子:

int foo::bar(int x)
{
 // a whole lot of code here
 return 2 * x + 4;
}

在代码库中被广泛使用。现在我需要将 4 变成一个参数,但是任何已经调用 foo::bar 的代码仍然应该收到它所期望的。我是否应该扩展并重命名旧方法并将其包装成一个新方法,例如

int foo::extended_bar(int x, int y)
{
 // ...
 return 2 * x + y;
}

int foo::bar(int x)
{
 return extended_bar(x,4);
}

或者我应该在头文件中声明一个默认参数,比如

int bar(int x, int y=4);

并且只是扩展功能

int foo::bar(int x, int y)
{
 // ...
 return 2 * x + y;
}

每个变体的优点和缺点是什么?

4

3 回答 3

8

我通常使用包装函数(大部分时间通过重载)而不是默认参数。

原因是向后兼容有两个级别:

  1. 具有源级向后兼容性意味着您必须重新编译调用代码而不进行更改,因为新函数签名与旧函数签名兼容。两者都可以达到这个水平;默认值和包装器/重载。

  2. 更强的级别是二进制级别的向后兼容性,它甚至可以在不重新编译的情况下工作,例如当您无权访问调用代码时。想象一下,您以二进制形式部署您的函数,例如在 DLL 等中。在这种情况下,签名必须完全相同才能使其工作,而默认值并非如此——它们会破坏这种级别的兼容性.

包装函数的另一个优点是 - 如果您的应用程序有任何类型的日志记录 - 您可以在旧函数中转储一个警告,指出它将在未来版本中过时,并且建议使用新函数。

于 2009-06-02T17:40:10.360 回答
0

我使用 C++ 的时间越长,我就越不喜欢默认函数参数。我无法确定我不喜欢的任何具体原因,但我发现如果我使用它们,我几乎总是会在以后删除它们。所以我的(主观)投票支持新的命名函数——名称当然可以与旧函数的名称相同。

于 2009-06-02T17:45:48.510 回答
0

我个人认为,隐性行为是万恶之源(之一)。

任何让维护者或调用者混淆被调用目标的身份的东西都应该有非常充分的理由,尤其是当它是主要 API 的一部分时。

因此,我强烈反对使用默认操作的选项。

此外,我相信如果可以使用不同数量的参数调用某个函数,那么这两个版本的函数在本质上会有所不同,或者它们做得太多。区别可能应该在名称中,并且可能比“_extended”更有意义

于 2009-06-02T18:06:40.380 回答