Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лекции / Лекции 1-2.docx
Скачиваний:
0
Добавлен:
11.02.2026
Размер:
142.98 Кб
Скачать

Предупреждение о функции exit()

Если вы используете функцию exit(), то ваша программа завершится, и никакие деструкторы не будут вызваны.

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

Используя конструкторы и деструкторы, ваши классы могут выполнять инициализацию и очистку после себя автоматически без вашего участия! Это уменьшает вероятность возникновения ошибок и упрощает процесс использования классов.

Скрытый указатель this

Один из частых вопросов по поводу классов: «При вызове метода класса, как C++ отслеживает то, какой объект его вызвал?».

Ответ заключается в том, что C++ для этих целей использует скрытый указатель  this!

Скрытый указатель *this

Ниже приведен простой класс, который содержит целочисленное значение и имеет конструктор и функции доступа.

Обратите внимание, деструктор здесь не нужен, так как язык C++ может очистить память переменной-члена самостоятельно:

#include <iostream>

class Another {

private:

Int m_number;

public:

Another(int number) {

setNumber(number);

}

void setNumber(int number) { m_number = number; }

Int getNumber() { return m_number; }

};

Int main() {

Another another(3);

another.setNumber(4);

std::cout << another.getNumber() << '\n';

return 0;

}

Результат выполнения программы:

4

При вызове another.setNumber(4)  C++ понимает, что функция setNumber() работает с объектом another, а m_number — это фактически another.m_number. Рассмотрим детально, как это всё работает.

Возьмем, к примеру, следующую строку:

another.setNumber(4);

Хотя на первый взгляд кажется, что у нас здесь только один аргумент, но на самом деле у нас их два!

Во время компиляции строка  another.setNumber(4); конвертируется компилятором в следующее:

setNumber(&another, 4); // объект another конвертировался из объекта, который находился перед точкой, в аргумент функции!

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

Но это только половина дела. Поскольку в вызове функции теперь есть два аргумента, то и метод нужно изменить соответствующим образом (чтобы он принимал два аргумента).

Следовательно, следующий метод:

void setNumber(int number) { m_number = number; }

Конвертируется компилятором в:

void setNumber(Another* const this, int number) { this->m_number = number; }

При компиляции обычного метода, компилятор неявно добавляет к нему параметр this. 

Указатель this — это скрытый константный указатель, содержащий адрес объекта, который вызывает метод класса.

Есть еще одна деталь. Внутри метода также необходимо обновить все члены класса (функции и переменные), чтобы они ссылались на объект, который вызывает этот метод.

Это легко сделать, добавив префикс this-> к каждому из них.

Таким образом, в теле функции setNumber(), m_number (переменная-член класса) будет конвертирована в this->m_number.

И когда this “указывает” на адрес another, то this->m_number будет указывать на another.m_number.

Соединяем всё вместе:

  При вызове another.setNumber(4) компилятор фактически вызывает setNumber(&another, 4).    Внутри setNumber() указатель this содержит адрес объекта another.

    К любым переменным-членам внутри setNumber() добавляется префикс this->. Поэтому, когда мы говорим m_number = number, компилятор фактически выполняет this->m_number = number, который, в этом случае, обновляет another.m_number на number.

Хорошо то, что это всё происходит скрыто от нас (программистов), и не имеет значения, помните ли вы, как это работает или нет.

Всё, что вам нужно запомнить — все обычные методы класса имеют указатель this, который указывает на объект, связанный с вызовом метода класса.