1

Let the source code speak for itself:

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

Compiler generates following error:

E2015 Ambiguity between 'MLine::MLine(int,int,int,int) at shapes.h:100' and 'MLine::MLine(double,double,double,double) at shapes.h:110'

I can resolve this problem by following explicit casting:

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

The partial casting is not sufficient:

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

I am quite confused about rules for implicit casting in expressions. Can someone explain this behaviour? What is the data type of expressions 'x - length_x1' and 'y - length_y1'?

4

2 回答 2

2

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

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

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

X         => int
length_x1 => double

所以种类也不一样。因此将提升一个对象。在这种情况下,X 将被提升为双精度(为什么要查找提升规则)。运算符 - 将被应用,结果是双精度数。

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

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

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

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

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

于 2012-04-17T09:05:42.303 回答
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); }

-> 有效,因为只有一个候选者,并且 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); }

-> 使用第二个版本,因为它是完全匹配的。

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

-> 注意:这一次,我们传递一个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
}
于 2012-04-17T09:04:46.043 回答