扩展现有API:使用默认参数或包装函数?

时间:2009-06-02 17:38:58

标签: c++ backwards-compatibility

我有一个现有的方法(或一般的功能),我需要增加其他功能,但我不想在代码的其他地方使用该方法。例如:

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;
}

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

3 个答案:

答案 0 :(得分:7)

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

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

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

  2. 更强的级别是二进制级向后兼容性,甚至可以在不重新编译的情况下工作,例如:当您无法访问调用代码时。想象一下,你以二进制形式部署你的函数,就像在DLL等中一样。在这种情况下,签名具有完全相同的功能,使其无效 - 默认值不是这样 - 它们将破坏这种兼容性水平

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我个人认为隐性行为是(一种)所有邪恶的根源。

任何使维护者或调用者混淆被调用目标的身份应该具有非常强大的理由,特别是如果它是主要API的一部分。

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

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