3

这个 C++ 问题似乎非常基本和一般,但我仍然希望有人回答。

1) 具有可变长度参数的函数和重载函数有什么区别?2)如果我们有一个具有可变长度参数的函数和另一个具有相似参数的同名函数,我们会有问题吗?

4

4 回答 4

7

2)你的意思是以下吗?

int mul(int a, int b);
int mul(int n, ...);

让我们假设第一个乘以 2 个整数。第二个乘以nvar-args 传递的整数。调用 withf(1, 2)不会有歧义,因为通过“省略号”传递的参数与可能的最高成本相关联。然而,将参数传递给相同类型的参数与可能的最低成本相关联。所以这个调用肯定会被解析为第一个函数:)


请注意,重载决议仅将参数与相同位置的参数转换进行比较。如果某个参数对的任何一个函数都有获胜者,它将很难失败。例如

int mul(int a, int b);
int mul(double a, ...);

想象一下,第一个乘以两个整数,第二个乘以一个以 a 结尾的双精度列表0.0。这个重载集是有缺陷的,当被调用时会模棱两可

mul(3.14, 0.0); 

这是因为第二个函数赢得了第一个参数,但第一个函数赢得了第二个参数。第二个函数的第二个参数的转换成本高于第一个函数的第一个参数的成本并不重要。一旦确定了这样一个“交叉”获胜者的情况,对这两个候选人的呼吁就变得模棱两可了。

于 2009-10-14T15:05:18.367 回答
1

1) 一个重载的函数需要大量不同的原型和实现。它也将是类型安全的。
2)是的,这会给你带来问题,因为编译器不知道它需要调用哪个函数。它可能会或可能不会对此发出警告。如果不是这样,您最终可能会很难找到错误。

于 2009-10-14T15:00:52.453 回答
1

一个重载的函数可以有完全不同的参数类型,包括没有,根据参数类型选择正确的类型。

可变长度参数要求至少存在一个参数。您还需要一些机制来“预测”下一个参数的类型(因为您必须在 中声明它va_arg()),并且它必须是基本类型(即整数、浮点或指针)。这里的常用技术是“格式字符串”(如printf(), scanf())或“标记列表”(参数列表中的每个奇数元素都是一个枚举,告诉后面的偶数元素的类型,用零枚举标记参数的结尾列表)。

一般来说,重载是 C++ 的方式。如果您最终确实需要类似于 C++ 中的可变长度参数列表的东西,例如为了方便地链接各种数量和类型的参数,请考虑 C++ 流的工作方式(那些连接的“<<”和“>>”):

class MyClass {
    public:
        MyClass & operator<<( int i )
        {
            // do something with integer
            return *this;
        }

        MyClass & operator<<( double d )
        {
            // do something with float
            return *this;
        }
};

int main()
{
    MyClass foo;
    foo << 42 << 3.14 << 0.1234 << 23;
    return 0;
}
于 2009-10-14T15:15:24.163 回答
0

它非常笼统,Goz 已经涵盖了一些要点。还有几个:

1) 如果您传递除 POD 对象之外的任何内容,则变量参数列表会给出未定义的行为。重载的函数可以接收任何类型的对象。

2) 如果重载集的一个成员采用可变参数列表,您可能会产生歧义。再说一次,如果没有它,你也会有歧义。但是,变量参数列表可能会在大量情况下产生歧义。

第一点是非常严重的——对于大多数实际目的,它使变量参数列表纯粹是 C++ 中的“遗留”项,甚至不考虑在任何新代码中使用。最常见的替代方法是链接重载运算符(例如 iostream 插入器/提取器与 printf/scanf)。

于 2009-10-14T15:13:46.343 回答