Reputation: 73
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?
Upvotes: 3
Views: 137
Reputation: 114461
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.
Upvotes: 2
Reputation: 476970
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 generally 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);
Upvotes: 4
Reputation: 153909
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.)
Upvotes: 1
Reputation: 881243
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.
Upvotes: 1
Reputation: 392911
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);
Upvotes: 1