Перегрузка операторов
Ключевое слово operator позволяет изменить работу конкретного оператора с экземплярами класса. Это дает оператору дополнительное значение — "перегружает" его. Компилятор различает разные значения оператора, проверяя типы его операндов.
В примере оператор + перегружается для сложения двух комплексных чисел.
➡️ @cpp_geek
Ключевое слово operator позволяет изменить работу конкретного оператора с экземплярами класса. Это дает оператору дополнительное значение — "перегружает" его. Компилятор различает разные значения оператора, проверяя типы его операндов.
В примере оператор + перегружается для сложения двух комплексных чисел.
➡️ @cpp_geek
this является const указателем
Указатель this является неизменяемым указателем. Убедимся это на примере:
class Foo {
private:
int x;
public:
Foo(int x = 0) { this->x = x; }
void change(Foo *foo) { this = foo; }
void print() { cout << x << endl; }
};
Здесь в методе change мы пытаемся присвоить указателю this новое значение.
Попробуем вызвать метод change в методе main:
Foo obj (3);
Foo *ptr;
obj.change(ptr);
obj.print();
Если мы запустим код, то получим ошибку компиляции в методе change (lvalue required as left operand of assignment). Компилятор не позволяет нам изменить значение указателя this.
➡️ @cpp_geek
Указатель this является неизменяемым указателем. Убедимся это на примере:
class Foo {
private:
int x;
public:
Foo(int x = 0) { this->x = x; }
void change(Foo *foo) { this = foo; }
void print() { cout << x << endl; }
};
Здесь в методе change мы пытаемся присвоить указателю this новое значение.
Попробуем вызвать метод change в методе main:
Foo obj (3);
Foo *ptr;
obj.change(ptr);
obj.print();
Если мы запустим код, то получим ошибку компиляции в методе change (lvalue required as left operand of assignment). Компилятор не позволяет нам изменить значение указателя this.
➡️ @cpp_geek
Библиотечный метод
Продемонстрируйте работу метода сортировки вставками по возрастанию. Для этого выведите состояние данного массива после каждой вставки на отдельных строках. Если массив упорядочен изначально, не нужно ничего выводить.
Формат входных данных:
На первой строке дано целое число n (1 ≤ n ≤ 100) – количество элементов в массиве. На второй строке задан сам массив: последовательность натуральных чисел, не превышающих 10^9.
Формат выходных данных:
В выходной файл выведите строки (по количеству вставок) по n чисел каждая.
➡️ @cpp_geek
Продемонстрируйте работу метода сортировки вставками по возрастанию. Для этого выведите состояние данного массива после каждой вставки на отдельных строках. Если массив упорядочен изначально, не нужно ничего выводить.
Формат входных данных:
На первой строке дано целое число n (1 ≤ n ≤ 100) – количество элементов в массиве. На второй строке задан сам массив: последовательность натуральных чисел, не превышающих 10^9.
Формат выходных данных:
В выходной файл выведите строки (по количеству вставок) по n чисел каждая.
➡️ @cpp_geek
Общие хитрости для C++
Никогда не используйте INT_MAX в качестве бесконечности для целых чисел. В некоторых алгоритмах, например, Флойда–Уоршелла, используются значения вроде ∞+w, что приведёт к переполнению при использовании INT_MAX. Вместо этого лучше использовать int oo = 0x3f3f3f3f, поскольку:
• Это число достаточно большое для задач, связанных с целыми числами;
• 2 * oo не приведёт к переполнению;
• Все байты равны, поэтому вы без проблем можете использовать memset(array, oo, sizeof(array));
• Его довольно легко запомнить.
Однако будьте осторожны: не используйте 0x3f3f3f3f для long long, так как в таком случае фокус уже не пройдёт, и вы потом потратите кучу времени на поиск ошибки.
➡️ @cpp_geek
Никогда не используйте INT_MAX в качестве бесконечности для целых чисел. В некоторых алгоритмах, например, Флойда–Уоршелла, используются значения вроде ∞+w, что приведёт к переполнению при использовании INT_MAX. Вместо этого лучше использовать int oo = 0x3f3f3f3f, поскольку:
• Это число достаточно большое для задач, связанных с целыми числами;
• 2 * oo не приведёт к переполнению;
• Все байты равны, поэтому вы без проблем можете использовать memset(array, oo, sizeof(array));
• Его довольно легко запомнить.
Однако будьте осторожны: не используйте 0x3f3f3f3f для long long, так как в таком случае фокус уже не пройдёт, и вы потом потратите кучу времени на поиск ошибки.
➡️ @cpp_geek
Сколько в памяти занимает произвольная структура?
Ответ: sizeof всех членов + остаток для выравнивания (по умолчанию выравнивание 4 байта) + sizeof указателя на vtable (если есть виртуальные функции) + указатели на классы предков, от которых было сделано виртуальное наследование (размер указателя * количество классов).
➡️ @cpp_geek
Ответ: sizeof всех членов + остаток для выравнивания (по умолчанию выравнивание 4 байта) + sizeof указателя на vtable (если есть виртуальные функции) + указатели на классы предков, от которых было сделано виртуальное наследование (размер указателя * количество классов).
➡️ @cpp_geek
Введение в обработку исключений
Одним из преимуществ C++ перед C является обработка исключений. Исключения - это ненормальные условия, с которыми программа сталкивается во время своего выполнения.
Есть два типа исключений: а) синхронные, б) асинхронные (например, которые находятся вне контроля программы, сбой диска и т. д.). Для этой цели C++ предоставляет следующие специализированные ключевые слова.
try: представляет блок кода, который может вызвать исключение.
catch: представляет блок кода, который выполнится при возникновении определенного исключения.
throw: используется для создания исключения. Также используется для перечисления исключений, которые генерирует функция, но не обрабатывает себя.
➡️ @cpp_geek
Одним из преимуществ C++ перед C является обработка исключений. Исключения - это ненормальные условия, с которыми программа сталкивается во время своего выполнения.
Есть два типа исключений: а) синхронные, б) асинхронные (например, которые находятся вне контроля программы, сбой диска и т. д.). Для этой цели C++ предоставляет следующие специализированные ключевые слова.
try: представляет блок кода, который может вызвать исключение.
catch: представляет блок кода, который выполнится при возникновении определенного исключения.
throw: используется для создания исключения. Также используется для перечисления исключений, которые генерирует функция, но не обрабатывает себя.
➡️ @cpp_geek
Как включить все стандартные библиотеки одной командой
Чтобы разом включить в проект все стандартные библиотеки, используйте #include <bits/stdc++.h>. Это особенно полезно в условиях дефицита времени на соревнованиях по программированию.
Но помните, что:
#include <bits/stdc++.h>
содержит множество заголовочных файлов, которые, возможно, и не понадобятся в конкретном проекте. А это может привести к увеличению времени компиляции.
#include <bits/stdc++.h> не является стандартным заголовочным файлом библиотеки GNU C++. Таким образом, не относящиеся к типу GCC (GNU Compiler Collection) компиляторы могут испытывать затруднения в процессе исполнения. Однако так бывает не часто!
➡️ @cpp_geek
Чтобы разом включить в проект все стандартные библиотеки, используйте #include <bits/stdc++.h>. Это особенно полезно в условиях дефицита времени на соревнованиях по программированию.
Но помните, что:
#include <bits/stdc++.h>
содержит множество заголовочных файлов, которые, возможно, и не понадобятся в конкретном проекте. А это может привести к увеличению времени компиляции.
#include <bits/stdc++.h> не является стандартным заголовочным файлом библиотеки GNU C++. Таким образом, не относящиеся к типу GCC (GNU Compiler Collection) компиляторы могут испытывать затруднения в процессе исполнения. Однако так бывает не часто!
➡️ @cpp_geek
Для чего нужен аллокатор и как создать свой собственный аллокатор?
Аллокатор это шаблонный класс, который отвечает за выделение памяти и создание объектов. По умолчанию все контейнера используют std::allocator<T>.
В языке c++ имеется так же возможность написать свой аллокатор. У своего алокатора должно быть такое объявление(см картинку).
➡️ @cpp_geek
Аллокатор это шаблонный класс, который отвечает за выделение памяти и создание объектов. По умолчанию все контейнера используют std::allocator<T>.
В языке c++ имеется так же возможность написать свой аллокатор. У своего алокатора должно быть такое объявление(см картинку).
➡️ @cpp_geek
Могут ли статические функции быть виртуальными в C++?
В C++ статическая функция-член класса не может быть виртуальной.
Кроме того, статические функции-члены класса не могут быть
В примере кода приведены две функции, обе из которых не дадут программе скомпилироваться.
➡️ @cpp_geek
В C++ статическая функция-член класса не может быть виртуальной.
Кроме того, статические функции-члены класса не могут быть
const
и volatile
. В примере кода приведены две функции, обе из которых не дадут программе скомпилироваться.
➡️ @cpp_geek
Объявление вложенных пространств имён
Избегайте вложенности пространств имён, а если не избежать, то объявляйте их так(см картинку).
Подробнее https://learn.microsoft.com/ru-ru/cpp/cpp/namespaces-cpp?view=msvc-160
➡️ @cpp_geek
Избегайте вложенности пространств имён, а если не избежать, то объявляйте их так(см картинку).
Подробнее https://learn.microsoft.com/ru-ru/cpp/cpp/namespaces-cpp?view=msvc-160
➡️ @cpp_geek
Алгоритм is_partitioned
Используется для определения того, разделен ли диапазон [first, last) или нет. Говорят, что диапазон разделен относительно условия, если все элементы, для которых условие оценивается как истинное, предшествуют тем, для которых оно является ложным.
➡️ @cpp_geek
Используется для определения того, разделен ли диапазон [first, last) или нет. Говорят, что диапазон разделен относительно условия, если все элементы, для которых условие оценивается как истинное, предшествуют тем, для которых оно является ложным.
➡️ @cpp_geek
Алгоритм stable_partition
Упорядочивает последовательность, определенную параметрами
➡️ @cpp_geek
Упорядочивает последовательность, определенную параметрами
start
и end
, так, чтобы все элементы, для которых предикат возвращал true
, предшествовали тем, для которых предикат возвращает false
. Разметка стабильная. Это означает, что относительный порядок последовательности сохраняется.➡️ @cpp_geek
Алгоритм merge
Объединяет две отсортированные последовательности, ограниченные диапазонами
Шаблон:
➡️ @cpp_geek
Объединяет две отсортированные последовательности, ограниченные диапазонами
[first1,last1)
и [first2,last2)
, в единую отсортированную последовательность, начинающуюся с позиции result.Шаблон:
merge (initer1 beg1, initer1 end1,
initer2 beg2, initer2 end2,
outiter res).
➡️ @cpp_geek
Некоторые различия между ссылками и указателями
1. Указатель может быть объявлен
2. Переменная-указатель может иметь несколько уровней вложенности, то есть, например, бывают одиночные указатели, двойные указатели, тройные указатели. Ссылка же имеет только один единственный уровень вложенности.
3. Ссылочная переменная не может быть обновлена.
➡️ @cpp_geek
1. Указатель может быть объявлен
void
, а ссылка - никогда. Пример на картинке.2. Переменная-указатель может иметь несколько уровней вложенности, то есть, например, бывают одиночные указатели, двойные указатели, тройные указатели. Ссылка же имеет только один единственный уровень вложенности.
3. Ссылочная переменная не может быть обновлена.
➡️ @cpp_geek
Указатели с ключевыми словами const и volatile
Ключевые слова const и volatile изменяют то, как обрабатываются указатели. const указывает, что данные по указателю не могут быть изменены после инициализации; volatile указывает, что значение может быть изменено действиями, отличными от тех, которые указаны в пользовательском приложении.
volatile полезно для объявления объектов в общей памяти, к которым могут обращаться несколько процессов или для глобальных областей данных.
➡️ @cpp_geek
Ключевые слова const и volatile изменяют то, как обрабатываются указатели. const указывает, что данные по указателю не могут быть изменены после инициализации; volatile указывает, что значение может быть изменено действиями, отличными от тех, которые указаны в пользовательском приложении.
volatile полезно для объявления объектов в общей памяти, к которым могут обращаться несколько процессов или для глобальных областей данных.
➡️ @cpp_geek