Грокаем C++
@grokaemcpp
Дефолтный конструктор. Введение
#новичкам
Описание корректного интерфейса создания объекта - важная часть проектирования класса. Поэтому надо понимать нюансики работы с конструкторами, чтобы все правильно организовать.
Ну и конечно самый базовый и, потенциально, самый сложный с точки зрения языка - конструктор по-умолчанию.
Казалось бы, у Example вообще не определено ни одного конструктора. Но тем не менее объект успешно создался. Как так?
Дефолтный конструктор умеет за вас генерировать сам компилятор.
А почему бы и нет? Смотря со стороны даже вполне логично и понятно, что он должен делать: вызывать конструкторы по умолчанию для всех нестатических членов и базовых классов в порядке объявления. Если мне от дефолтного конструктора нужно только это, то я могу просто положиться на компилятор.
Таким образом конструктор по-умолчанию входит в число специальных методов классов, которые компилятор сам умеет генерить.
Однако, не все так просто.
Как только вы определите хотя бы один другой конструктор, компилятор перестанет генерить дефолтный:
Оно и понятно: если вы не определяли никакой конструктор, значит вы довольны дефолтным поведением. Но как только вы сами определили конструктор, вы сказали компилятору, что дефолтное поведение вам не подходит и вы берете ответственность за способы создания объектов этого класса.
И компилятор не смеет перечить вашей задумке. Очень может быть, что вы хотите, чтобы Example2 создавался только через параметрический конструктор и больше никак. По сути, именно это и прописано сейчас в классе. Если бы компилятор неявно добавил конструктор по-умолчанию, то это нарушило бы контракт вашего класса.
Если вы все-таки хотите, чтобы у вас была возможность создать объект по-умолчанию, то вам явно нужно добавить конструктор без аргументов:
О том, какую роль 50 оттенков конструктора по-умолчанию при обращении с объектами классов, мы поговорим в следующем посте.
Don't be trivial. Stay cool.
#cppcore
#новичкам
Описание корректного интерфейса создания объекта - важная часть проектирования класса. Поэтому надо понимать нюансики работы с конструкторами, чтобы все правильно организовать.
Ну и конечно самый базовый и, потенциально, самый сложный с точки зрения языка - конструктор по-умолчанию.
class NoConstructor {
int total;
public:
void accumulate (int x) { total += x; }
};
Example ex;Казалось бы, у Example вообще не определено ни одного конструктора. Но тем не менее объект успешно создался. Как так?
Дефолтный конструктор умеет за вас генерировать сам компилятор.
А почему бы и нет? Смотря со стороны даже вполне логично и понятно, что он должен делать: вызывать конструкторы по умолчанию для всех нестатических членов и базовых классов в порядке объявления. Если мне от дефолтного конструктора нужно только это, то я могу просто положиться на компилятор.
Таким образом конструктор по-умолчанию входит в число специальных методов классов, которые компилятор сам умеет генерить.
Однако, не все так просто.
Как только вы определите хотя бы один другой конструктор, компилятор перестанет генерить дефолтный:
class ParametrizedConstructor {
int total;
public:
ParametrizedConstructor(int initial_value) : total(initial_value) { };
void accumulate (int x) { total += x; };
};
ParametrizedConstructor ex (100); // ok
ParametrizedConstructor ex1; // error: no default constructorОно и понятно: если вы не определяли никакой конструктор, значит вы довольны дефолтным поведением. Но как только вы сами определили конструктор, вы сказали компилятору, что дефолтное поведение вам не подходит и вы берете ответственность за способы создания объектов этого класса.
И компилятор не смеет перечить вашей задумке. Очень может быть, что вы хотите, чтобы Example2 создавался только через параметрический конструктор и больше никак. По сути, именно это и прописано сейчас в классе. Если бы компилятор неявно добавил конструктор по-умолчанию, то это нарушило бы контракт вашего класса.
Если вы все-таки хотите, чтобы у вас была возможность создать объект по-умолчанию, то вам явно нужно добавить конструктор без аргументов:
class ParametrizedAndDefaultConstructor {
int total;
public:
ParametrizedAndDefaultConstructor() = default; // или так
ParametrizedAndDefaultConstructor() {} // или так
ParametrizedAndDefaultConstructor(int initial_value) : total(initial_value) { };
void accumulate (int x) { total += x; };
};
ParametrizedAndDefaultConstructor ex(100); // ok
ParametrizedAndDefaultConstructor ex1; // okParametrizedAndDefaultConstructor() = default; - вы явно определяете конструктор по-умолчанию, но так же явно просите компилятор о том, чтобы его поведение было как если бы сам компилятор его генерировал.ParametrizedAndDefaultConstructor() {/something/} - это вы уже самостоятельно определяете, какую дополнительную логику должен иметь этот конструктор. Он делает все то же самое, что и тривиальный, только вдобавок выполняется еще и то, что вы указали внутри фигурных скобок. Такой конструктор называется уже нетривиальным, даже если его тело в итоге оказалось пустым.О том, какую роль 50 оттенков конструктора по-умолчанию при обращении с объектами классов, мы поговорим в следующем посте.
Don't be trivial. Stay cool.
#cppcore
❤ 19
👍 13
🔥 6
❤🔥 1
24 15 3.1K
Обсуждение 24
Обсуждение не доступно в веб-версии. Чтобы написать комментарий, перейдите в приложение Telegram.
Обсудить в Telegram