- •Классы, Объекты и Методы
- •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;
- •Цепочки методов класса
- •Заключение
Предупреждение о функции 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, который указывает на объект, связанный с вызовом метода класса.
