- •Классы, Объекты и Методы
- •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;
- •Цепочки методов класса
- •Заключение
Указатель this всегда указывает на текущий объект. Явное указание указателя this
В большинстве случаев вам не нужно явно указывать указатель this. Тем не менее, иногда это может быть полезным.
Например, если у вас есть конструктор (или метод), который имеет параметр с тем же именем, что и переменная-член, то устранить неоднозначность можно с помощью указателя this:
class Something {
private:
Int data;
public:
Something(int data) {
this->data = data;
}
};
Здесь конструктор принимает параметр с тем же именем, что и переменная-член. В этом случае data относится к параметру, а this->data относится к переменной-члену. Хотя это приемлемая практика, но рекомендуется использовать префикс m_ для всех имен переменных-членов вашего класса, так как это помогает предотвратить дублирование имен в целом!
Цепочки методов класса
Иногда бывает полезно, чтобы метод класса возвращал объект, с которым работает, в виде возвращаемого значения.
Основной смысл здесь — это позволить нескольким методам объединиться в «цепочку», работая при этом с одним объектом!
Мы на самом деле пользуемся этим уже давно.
Например, когда мы выводим несколько данных с помощью std::cout:
std::cout << "Hello, " << userName;
В этом случае std::cout является объектом, а операция << — методом, который работает с этим объектом.
Компилятор обрабатывает фрагмент, приведенный выше, следующим образом:
(std::cout << "Hello, ") << userName;
Сначала операция << использует std::cout и строковый литерал Hello для вывода Hello в консоль.
Однако, поскольку это часть выражения, операция << также должен возвратить значение (или void). Если операция << возвращает void, то получается следующее:
(void) <<…
Что явно не имеет никакого смысла (компилятор выдаст ошибку). Однако, вместо этого, операция << возвращает разыменованный указатель *this, что в этом контексте является просто самим объектом std::cout. Таким образом, после обработки первого оператора <<, мы получаем:
(std::cout) << userName;
Что приводит к выводу имени пользователя (userName).
Таким образом, нам нужно указать объект (в данном случае, std::cout) один раз, и каждый вызов функции будет передавать этот объект следующей функции, что позволит нам объединить несколько методов вместе.
Мы сами можем реализовать такое поведение. Рассмотрим следующий класс:
class Mathem {
private:
int m_value;
public:
Mathem() { m_value = 0; }
void add(int value) { m_value += value; }
void sub(int value) { m_value -= value; }
void multiply(int value) { m_value *= value; }
int getValue() { return m_value; }
};
Если вы хотите добавить 7, вычесть 5 и умножить всё на 3, то нужно сделать следующее:
#include <iostream>
int main() {
Mathem operation;
operation.add(7); // возвращает void
operation.sub(5); // возвращает void
operation.multiply(3); // возвращает void
std::cout << operation.getValue() << '\n';
return 0;
}
Результат:
6
Однако, если каждая функция будет возвращать через указатель this сам объект- *this, то мы сможем связать эти вызовы методов в одну цепочку. Например:
class Mathem {
private:
int m_value;
public:
Mathem() { m_value = 0; }
Mathem& add(int value) { m_value += value; return *this; }
Mathem& sub(int value) { m_value -= value; return *this; }
Mathem& multiply(int value) { m_value *= value; return *this; }
int getValue() { return m_value; }
};
Обратите внимание, add(), sub() и multiply() теперь возвращают сам объект *this, поэтому следующее будет корректным:
#include <iostream>
int main() {
Mathem operation;
operation.add(7).sub(5).multiply(3);
std::cout << operation.getValue() << '\n';
return 0;
}
Результат:
6
Мы фактически вместили три отдельные строки в одно выражение! Теперь рассмотрим это детально:
Сначала вызывается operation.add(7), который добавляет 7 к нашему m_value.
Затем add() возвращает *this, который является ссылкой на объект operation.
Затем вызов operation.sub(5) вычитает 5 из m_value и возвращает operation.
multiply(3) умножает m_value на 3 и возвращает operation, который уже игнорируется.
Однако, поскольку каждая функция модифицировала operation, m_value объекта operation теперь содержит значение ((0 + 7) - 5) * 3), которое равно 6.
