Question

I've been asked this question in a job interview, and even after compiling it, I still don't understand the outcome...

I have the following class:

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

    double m_X, m_Y;
};

and main.cpp is:

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

The data members of class p are getting the values:

m_X = a+r*yCoord, m_Y = 0

Now, why is that?

Was it helpful?

Solution

Because of the comma operator and the non-explicit constructor. The expression (a + r * xCoord , a + r * yCoord) is an application of the comma operator and has the value a + r * yCoord, and now the one-parameter implicit form of your Point constructor is used with this value, and the second parameter is defaulted.

You can prevent such mistakes from creeping in by making the constructor explicit, which is gene­rally recommended for any constructor that can be called with one argument, unless you really want implicit conversions.

To get your desired behaviour, you want direct initialization:

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

OTHER TIPS

It's a trick question... the expression

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

is a comma operator expression so your code is actually

Point p = a+r*yCoord;

The constructor can be used as a conversion constructor (because is not explicit) and therefore that is the same as writing:

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

To get the "expected result" you should remove the equal sign and write

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

In general it's better to use two distinct constructors instead of relying on default arguments for example with:

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

You should always pay extra attention to constructors taking only one parameter (or to which you can pass only one parameter, like in your example) because unless they're declared explicit C++ can use them implicitly for conversions, sometimes in surprising ways.

One last remark is that it's strange that the comma operator used in the code didn't produce a warning because the first expression has no side effects and a compiler should be able to detect that this probably was a mistake.

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

The (expression) uses the comma operator, which evaluates all terms in sequence, returning the rightmost.

Correct forms would be

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

You may want to change

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

into

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

The former is using the comma operator to give you one value (the last one in the comma operator expression) which you then assign to your object, and this will set your x member to it and default your y member to zero.

The latter will call the constructor with the two arguments.

It's because you're using the conversion operator, double to Point. When you use copy initialization (initialization with an = sign), the expression to the right of the = is first converted to the type on the left, and then the copy constructor is used (conceptually, at least). There's no way of specifying more than one argument using copy initialization. So your expression on the right is (a + r*xCoord, a + r*yCoord). And the comma is the comma operator (not the comma punctuation), which evaluates its left hand argument, then its right hand argument, and has for results the results of its right hand argument. (And results of the left hand argument are thrown away.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top