'function1'和'function2'之间的歧义(C ++)

时间:2012-04-17 08:55:44

标签: c++ implicit-cast c++builder-xe ambiguous-call

让源代码说明一切:

MLine::MLine(int x1, int y1, int x2, int y2)
{
}

MLine::MLine(double x1, double y1, double x2, double y2)
{
}

void __fastcall TVctDiag2::PrepareArrowTail(int x, int y)
{
    double length_x1;
    double length_y1;
    MLine *line = new MLine(x, y, x - length_x1, y - length_y1);
}

编译器生成以下错误:

E2015 shapes.h上的'MLine :: MLine(int,int,int,int)在shapes.h:100'和'MLine :: MLine(double,double,double,double)之间的歧义。 / p>

我可以通过以下显式转换来解决此问题:

    MLine *line = new MLine((double)x, (double)y, x - length_x1, y - length_y1);

部分施法是不够的:

    MLine *line = new MLine((double)x, y, x - length_x1, y - length_y1);

我对表达式中隐式转换的规则感到很困惑。有人可以解释这种行为吗?表达式'x - length_x1'和'y - length_y1'的数据类型是什么?

2 个答案:

答案 0 :(得分:2)

  

我对表达式中隐式转换的规则感到很困惑。有人可以解释这种行为吗?

二元运算符(+ - * / etc)处理相同类型的操作数(并返回与其操作数相同类型的结果)。如果类型不相同,那么将提升一个(通常但有时两个),以便两个操作数具有相同的类型。

  

表达式'x - length_x1'和'y - length_y1'的数据类型是什么?

X         => int
length_x1 => double

所以类型不一样。因此将推广一个对象。在这种情况下,X将被提升为double(为什么要查找promotion rules)。操作员 - 将被应用,结果是双倍。

如果我们现在看看你的表达:

MLine *line = new MLine(x, y, x - length_x1, y - length_y1);

如果我现在用它们的类型替换子表达式:

MLine *line = new MLine(<int>, <int>, <double>, <double>);

您现在可以看到编译器的困境。它无法知道选择哪个版本的构造函数(两者都可以通过应用一轮投射来实现)。所以它必须产生错误。

答案 1 :(得分:1)

MLine *line = new MLine((double)x, y, x - length_x1, y - length_y1);

这不起作用的原因是因为派生的类型是:

MLine(double, int, double, double)

这是因为......

促销

在具有混合操作数的操作中,操作数可能会转换为其他类型。对于浮点类型与整数类型的操作,首先将整数转换为浮点类型:

float f; int i;
f + i;

f + i的类型为float,因为在添加之前,i会转换为float

此促销活动导致......

歧义

没有完全匹配,并且重载候选是不明确的。

从技术上(和简化),C ++编译器将使用完全匹配,或从一组重载候选中选择最佳匹配。这些规则并不重要(一个衡量标准是所需的转换次数)。

让我举一些例子:

void foo (int) {}
int main () { foo(5.f); }

- &GT; Works,因为只有一个候选者,而double可以隐式转换为int。

#include <iostream>
void foo (int) { std::cout << "foo(int)\n"; }
void foo (float) { std::cout << "foo(float)\n"; }
int main () { foo(5.f); }

- &GT;使用第二个版本,因为它完全匹配。

#include <iostream>
void foo (int) { std::cout << "foo(int)\n"; }
void foo (float) { std::cout << "foo(float)\n"; }
int main () { foo(5.); }

- &GT;注意:这次,我们传递double。它不会编译,因为两个重载都需要转换,不是完全匹配,因此,候选是不明确的。

多个参数相同:

#include <iostream>
void foo (int,int) { std::cout << "foo(int,int)\n"; }
void foo (float,float) { std::cout << "foo(float,float)\n"; }
int main () { 
    foo(5.f, 5.f); // exact match with the (float,float) overload
    foo (5, 5);    // exact match with the (int,int) overload
    foo (5, 5.f);  // No exact match, and candidates are ambiguous
}