Параметры по умолчанию для функции в переполнении стека

Мне задавали этот вопрос на собеседовании, и даже после его составления я до сих пор не понимаю результата …

У меня есть следующий класс:

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

Теперь, почему это?

3

Решение

Из-за оператора запятой и неявного конструктора. Выражение (a + r * xCoord , a + r * yCoord) является приложением оператора запятой и имеет значение a + r * yCoordи теперь однопараметрическая неявная форма вашего Point конструктор используется с этим значением, а второй параметр по умолчанию.

Вы можете предотвратить появление таких ошибок, сделав конструктор explicit, который обычно рекомендуется для любого конструктора, который может быть вызван с одним аргументом, если вы действительно не хотите неявных преобразований.

Чтобы получить желаемое поведение, вы хотите прямую инициализацию:

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

Другие решения

Это вопрос с подвохом … выражение

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

это comma operator выражение, так что ваш код на самом деле

Point p = a+r*yCoord;

Конструктор может использоваться как конструктор преобразования (потому что не 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) { }
};

Вы всегда должны обращать особое внимание на конструкторы, принимающие только один параметр (или которому вы можете передать только один параметр, как в вашем примере), потому что, если они не объявлены explicit C ++ может использовать их неявно для преобразований, иногда удивительным образом.

Последнее замечание заключается в том, что странно, что оператор запятой, использованный в коде, не выдал предупреждение, потому что первое выражение не имеет побочных эффектов, и компилятор должен быть в состоянии обнаружить, что это, вероятно, было ошибкой.

2

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

Вы можете изменить

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

в

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

Первый использует оператор запятой, чтобы дать вам один значение (последнее в выражении оператора запятой), которое вы затем назначаете своему объекту, и это установит ваш x член к нему и по умолчанию ваш y член к нулю.

Последний вызовет конструктор с двумя аргументами.

1

Это потому, что вы используете оператор преобразования, double в
Point, При использовании инициализации копирования (инициализация с
= знак), выражение справа от = первый
преобразован в тип слева, а затем конструктор копирования
используется (концептуально, по крайней мере). Там нет никакого способа указать
более одного аргумента с использованием инициализации копирования. Так что ваши
выражение справа (a + r*xCoord, a + r*yCoord), А также
запятая это запятая оператор (не запятая),
который оценивает свой левый аргумент, а затем правую
аргумент, и имеет для результатов результаты его правой руки
аргумент. (И результаты левого аргумента брошены
далеко.)

1
По вопросам рекламы [email protected]