- •Классы, Объекты и Методы
- •Struct DateStruct {
- •Int month;
- •Int year;
- •Методы классов
- •Void print () {
- •Int main () {
- •Int main () {
- •Int main () {
- •Спецификаторы доступа public и private
- •Int year; // открыто по умолчанию
- •Int main () {
- •Int main () {
- •Int main ()
- •Структуры. Классы
- •Инкапсуляция, Геттеры и Сеттеры Инкапсуляция
- •Int m_array[10];
- •Int main () {
- •IntArray array;
- •Void setValue(int index, int value) {
- •Функции доступа (геттеры и сеттеры)
- •Int m_month;
- •Int m_year;
- •Int main () {
- •Краткий обзор l-value и r-value
- •Инициализация ссылок
- •Ссылки в качестве параметров в функциях
- •Void changeN (int &ref) {
- •Int main () {
- •Int value1;
- •Int otherValue;
- •Ссылки. Указатели
- •Конструкторы
- •Int main () {
- •Конструкторы по умолчанию
- •Конструкторы с параметрами
- •Int m_numerator;
- •Int m_denominator;
- •Int getNumerator () {return m_numerator; }
- •Int getDenominator () {return m_denominator; }
- •Копирующая инициализация
- •Уменьшение количества конструкторов
- •Неявно генерируемый конструктор по умолчанию
- •Int main () {
- •Int main () {
- •Классы, содержащие другие классы
- •Int main() {
- •Список инициализации членов класса
- •Списки инициализации членов класса
- •Int m_value1;
- •Values() {
- •Int m_value1;
- •Инициализация массивов в классе
- •Инициализация переменных-членов, которые являются классами
- •Int main() {
- •Использование списков инициализации
- •Int m_value1;
- •Int m_value1;
- •Int m_value1;
- •Порядок выполнения в списке инициализации
- •Инициализация нестатических членов класса
- •Void print() {
- •Int main() {
- •Void print() {
- •Int main() {
- •Void print() {
- •Int main() {
- •Void print() {
- •Int main() {
- •Делегирующие конструкторы
- •Void DoX() {
- •Init();
- •Init();
- •Void Init()
- •Int main() {
- •Ещё о делегирующих конструкторах
- •Деструкторы
- •Имена деструкторов
- •Пример использования деструктора на практике
- •Выполнение конструкторов и деструкторов
- •Int getId() { return m_nId; }
- •Int main() {
- •Предупреждение о функции exit()
- •Скрытый указатель this
- •Скрытый указатель *this
- •Int m_number;
- •Int getNumber() { return m_number; }
- •Int main() {
- •Указатель this всегда указывает на текущий объект. Явное указание указателя this
- •Int data;
- •Цепочки методов класса
- •Заключение
Void print() {
std::cout << "color: " << m_color << " and radius: " << m_radius << '\n';
}
};
Int main() {
Thing defl;
defl.print();
Thing red("red");
red.print();
Thing thirty(30.0);
thirty.print();
Thing redThirty("red", 30.0);
redThirty.print();
return 0;
}
Результат выполнения программы должен быть следующим:
color: blue and radius: 20
color: red and radius: 20
color: blue and radius: 30
color: red and radius: 30
Задание №2
Зачем мы объявили пустой конструктор по умолчанию в программе из задания №1?
Все же переменные-члены и так имеют значения по умолчанию.
Делегирующие конструкторы
Рассмотрим, что такое делегирующие конструкторы в языке С++, зачем они были придуманы и как их использовать.
Проблема
При создании нового объекта класса, компилятор C++ неявно вызывает конструктор этого объекта.
Не редкость встретить класс с несколькими конструкторами, которые частично выполняют одно и то же, например:
class Boo {
public:
Boo() {
// Часть кода X
}
Boo(int value) {
// Часть кода X
// Часть кода Y
}
};
Здесь есть 2 конструктора: конструктор по умолчанию и конструктор, который принимает целочисленное значение.
Поскольку Часть кода X требуется обоим конструкторам, то она дублируется в каждом из них.
А как вы уже могли догадаться, дублирование кода — это то, чего следует избегать, поэтому давайте рассмотрим возможные решения этой проблемы.
Решение в C++11
Неплохо было бы, чтобы конструктор Boo(int) вызывал конструктор Boo() для выполнения Часть кода X :
class Boo{
public:
Boo() {
// Часть кода X
}
Boo(int value) {
Boo(); // используем конструктор, указанный выше, для выполнения //части кода X
// Часть кода Y
}
};c:
Boo() {
Однако, если ваш компилятор не совместим с C++11, и вы попытаетесь вызвать один конструктор внутри другого конструктора, то это скомпилируется, но будет работать не так, как вы ожидаете.
До C+Использование отдельного метода
Конструкторам разрешено вызывать другие методы класса, которые не являются конструкторами.
Хотя у вас может возникнуть соблазн скопировать код из первого конструктора во второй конструктор, наличие дублированного кода сделает ваш класс более трудным для понимания и более обременительным для поддержки.
Лучшим решением будет, например, создание отдельного метода (не конструктора), который будет выполнять общую инициализацию, и оба конструктора будут вызывать этот метод. Например:
class Boo {
private:
Void DoX() {
// Часть кода X
}
public:
Boo() {
DoX();
}
Boo(int nValue) {
DoX();
// Часть кода Y
}
};
Здесь мы свели дублирование кода к минимуму.
Кроме того, вы можете оказаться в ситуации, когда вам нужно будет написать метод для повторной инициализации класса обратно до значений по умолчанию.
Поскольку у вас, вероятно, уже есть конструктор, который это делает, то у вас может возникнуть соблазн попытаться вызвать этот конструктор из вашего метода.
Однако это приведет к неожиданным результатам.
Многие разработчики просто копируют код из конструктора в функцию инициализации — это сработает, но приведет также к дублированию кода.
Лучшим решением будет переместить код из конструктора в вашу новую функцию и заставить конструктор вызывать вашу новую функцию для выполнения инициализации:
class Boo {
public:
Boo() {
