3

面试时被问过这个问题,编译后还是没看懂结果。。。

我有以下课程:

class Point
{
    public:
    Point(double x = 0, double y = 0) { m_X = x; m_Y = y; }

    double m_X, m_Y;
};

main.cpp 是:

int main()
{
    double a = 1, r = 1, xCoord = 5, yCoord = 7;

    Point p = (a+r*xCoord , a+r*yCoord);

    cout<<"X = "<<p.m_X<<" Y = "<<p.m_Y<<endl;

    return 0;
}

类 p 的数据成员正在获取值:

m_X = a+r*yCoord, m_Y = 0

现在,这是为什么呢?

4

5 回答 5

4

因为逗号运算符和非显式构造函数。该表达式(a + r * xCoord , a + r * yCoord)是逗号运算符的应用程序并具有值a + r * yCoord,现在Point构造函数的单参数隐式形式与此值一起使用,并且第二个参数是默认值。

您可以通过创建构造函数来防止此类错误蔓延explicit,这通常建议用于任何可以使用一个参数调用的构造函数,除非您真的想要隐式转换。

要获得所需的行为,您需要直接初始化:

Point p(a + r * xCoord, a + r * yCoord);
于 2013-03-04T08:25:40.530 回答
2

这是一个技巧问题...表达式

(a+r*xCoord , a+r*yCoord)

是一个comma operator表达式,所以你的代码实际上是

Point p = a+r*yCoord;

构造函数可以用作转换构造函数(因为 is not explicit),因此与编写相同:

Point p(a+r*yCoord, 0);

要获得“预期结果”,您应该删除等号并写入

Point p(a+r*xCoord , a+r*yCoord);

一般来说,最好使用两个不同的构造函数,而不是依赖默认参数,例如:

struct P2d {
    double x, y;
    P2d() : x(0), y(0) { }
    P2d(double x, double y) : x(x), y(y) { }
};

您应该始终特别注意仅采用一个参数的构造函数(或者您只能向其传递一个参数,就像在您的示例中一样),因为除非它们被声明,否则explicitC++ 可以隐式使用它们进行转换,有时以令人惊讶的方式。

最后一点是奇怪的是,代码中使用的逗号运算符没有产生警告,因为第一个表达式没有副作用,编译器应该能够检测到这可能是一个错误。

于 2013-03-04T08:27:36.797 回答
1
Point p = (a+r*xCoord , a+r*yCoord);

(表达式) 使用comma operator,它计算序列中的所有项,返回最右边的项。

正确的形式是

auto p = Point(a+r*xCoord , a+r*yCoord);
Point p(a+r*xCoord , a+r*yCoord);
于 2013-03-04T08:25:28.367 回答
1

这是因为您正在使用转换运算符doubleto Point。使用复制初始化(带=符号初始化)时,=首先将右边的表达式转换为左边的类型,然后使用复制构造函数(至少从概念上来说)。无法使用复制初始化指定多个参数。所以你右边的表达式是(a + r*xCoord, a + r*yCoord)。逗号是逗号运算符(不是逗号标点符号),它先计算左手参数,然后计算右手参数,并得到右手参数的结果。(并且左手参数的结果被丢弃。)

于 2013-03-04T08:28:43.997 回答
1

你可能想改变

Point p = (a+r*xCoord , a+r*yCoord);

进入

Point p (a+r*xCoord , a+r*yCoord);

前者使用逗号运算符为您提供一个值(逗号运算符表达式中的最后一个),然后您将其分配给您的对象,这会将您的x成员设置为它并将您的成员默认y为零。

后者将使用两个参数调用构造函数。

于 2013-03-04T08:26:20.543 回答