Подтвердить что ты не робот

Сколько конструкторов имеет класс?

Я готовлюсь к предстоящему экзамену С++ и наткнулся на этот вопрос о классах и конструкторах:

Сколько конструкторов имеет класс Fraction? "

class Fraction {
//...
public:
   Fraction(int numerator = 0, int denominator = 1);
//...
};

Я думал, что это только один, но они предположили, что есть три:

Fraction();
Fraction(n);
Fraction(n, d);

Или другими словами:
Является ли функция со значениями по умолчанию перегруженной функцией?

4b9b3361

Ответ 1

Существует только один конструктор, соответствующий объявленному объявлению, а не три перегрузки.

Вызов

Fraction();
Fraction(n);

эквивалентны:

Fraction(0, 1);
Fraction(n, 1);

Еще один способ убедить себя в том, что только один конструктор, соответствующий объявлению, состоит в том, что вам нужно определить только один конструктор, а не три.

В разделе стандарта С++ 11 по умолчанию используется следующее:

8.3.6 Аргументы по умолчанию

1 Если в объявлении параметра указано предложение initializer, это условие инициализатора используется в качестве аргумента по умолчанию. Аргументы по умолчанию будут использоваться в вызовах, где отсутствуют отсутствующие аргументы.

2 [Пример: объявление

void point(int = 3, int = 4);

объявляет функцию, которая может быть вызвана с нулевым, одним или двумя аргументами \type int. Его можно вызвать любым из следующих способов:

point(1,2); point(1); point();

Последние два вызова эквивалентны point(1,4) и point(3,4) соответственно. -end пример]

Теперь главный вопрос.

Сколько конструкторов имеет класс Fraction?

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

Ответ 2

Является ли функция со значениями по умолчанию перегруженной функцией?

Нет. Перегрузки выглядят как

Fraction();
Fraction(int numerator);
Fraction(int numerator, int denominator);

и имеют свою собственную реализацию (определение), а функция с параметрами по умолчанию имеет единственную реализацию.


Я думал, что это только один, но они предположили, что есть 3:...

"Сколько конструкторов имеет класс Fraction?"

Это трюк, призванный обмануть вас, показывая доступные варианты вызовов для одного объявления конструктора.

Ответ определенный для данного фрагмента кода 3 (в словах три).

Существует один специализированный конструктор (который обслуживает три варианта вызова), и компилятор автоматически создает конструктор копирования и перемещения, если вы не delete их, или предоставляете собственную реализацию:

Fraction(int numerator = 0, int denominator = 1); // (1)
// Redundant, just for demonstration:
Fraction(const Fraction& rhs) = default; // (2)
Fraction(Fraction&& rhs) = default; // (3)

Итак, для такого экзамена, если вы ответите

Класс имеет один конструктор

Это неправильно. Если вы ответите

В классе есть три конструктора (как вы написали, это принятый ответ)

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

Ответ 3

Ответ на ваш вопрос относится к этим трем последующим вопросам:

  • Перед С++ 11, С++ 11 или С++ 14 и далее?
  • Учитываются ли неявно определенные конструкторы?
  • Что представляют собой члены? Присутствие не скопируемого элемента удалит неявный конструктор копии.

Явное определение - это только один конструктор; компилятор будет вставлять вызов с тремя аргументами независимо от того, явно ли он содержит аргументы 0, 1 или 2.

В pre-'11 нет конструкторов перемещения, в '11 есть два неявных определения конструктора, Fraction(const Fraction &) noexcept и Fraction(Fraction &&) noexcept, проверьте доступные cppreference, в '14 правила того, когда изменяется неявно определенная конструкция конструктора перемещения.

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

Ответ 4

У вас есть только одно объявление конструктора.
С другой стороны:

Если для одного имени в одной и той же области указано два или более разных объявления, это имя считается перегруженным

Из-за этого я не использовал бы здесь перегруженный термин.

Ответ 5

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

Теперь сложно сказать, что мы говорим о конструкторе здесь, и конструктор не участвует в том же виде перегрузочного разрешения, что и обычная функция, и для всех целей не доступен, кроме синтаксически. В частности, это определение действительно учитывает отдельно как конструктор по умолчанию. Он также учитывается отдельно как конструктор преобразования из int и может использоваться как ((Фракция) 3).

Таким образом, для всех практических целей он создает три разных синтаксических объекта в категории конструкторов. И в отличие от обычных функций нет функционального контекста, в котором разрешение перегрузки могло бы выявить разницу между тремя действительными сигнатурами функций и тремя просто соглашениями синтаксического вызова.

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

Ответ 6

Потому что это зависит от аргументов, которые вы передаете:

Fraction() --> Fraction(0,1)
Fraction(n)---> Fraction(n,1)
Fraction(n,m)

Таким образом, он дает 3 конструктора. Здесь нет перегрузки.

Ответ 7

Вы можете создать объект Fraction тремя способами, используя один конструктор, объявленный в указанном выше классе. Конструктор имеет параметры по умолчанию. Если вы не передаете какой-либо аргумент, он принимает соответствующее значение для аргумента.

  • Fraction a; // числитель будет 0, а знаменатель будет 1

  • Fraction a(10); // числитель будет 10, а знаменатель будет 1

  • Fraction a(10, 20); // числитель будет 10, а знаменатель будет 20