user2130932
user2130932

Reputation: 73

Function Default Parameters in C++

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

Answers (5)

6502
6502

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

Kerrek SB
Kerrek SB

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

Upvotes: 4

James Kanze
James Kanze

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

paxdiablo
paxdiablo

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

sehe
sehe

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

Related Questions