- Объектно ориентированное программирование
- Абстракция - выделение значимой информации и исключение из рассмотрения незначимой
- Инкапсуляция - св-во системы объединить данные и методы
- Наследование - св-во системы, позволяющее описать новый класс на основе уже существующих
- Полиморфизм - св-во системы, позволяющее использовать объекты с одинаковым интерфейсом
- Полиморфизм - это способность функции обрабатывать данные разных типов. (За одним интерфейсом скрываются разные реализации)
- Умели только сторить поля
struct A {
int a;
char b;
double c;
};
A a;
a.a = 10;
a.b = 'c';
a.c = 1.1; class- кастомный data type, состоящий из набора полей и методов для взаимодействия с нимиsizeof(any instance of class) >= 1всегда (даже если классы stateless, т.е. без полей)
.- оператор для работы с объектами->- оператор для работы с указателями на объектthis- указатель на текущий объект (писать его не надо)
T second = first; // вызывается не operator=, а конструктор
explicit- запрет этого неявного каста (Vector a = 10;не равносильноVector(size: 10);)
struct A {
A(int a, int b = 10) {}
};
int main() {
A a = 10; // OK
return 0;
}- Также запрещает также неявный каст при вызове
operator Type()
struct Demo {
explicit operator bool() const { return true; }
};
int main() {
demo d;
if (d); // OK, вызывает Demo::operator bool()
bool b_d = d; // ОШИБКА: не может преобразовать 'Demo' в 'bool' во время инициализации
bool b_d = static_cast<bool>(d); // OK, явное преобразование, вы знаете, что делаете
}- Может принимать
constexpr-выражение:explicit(1 == 2)
- Будет проинициализировано в порядке указания полей в самом классе
Student(...) : name_(name), grade_(grade) { ... }
- Since C++11
S(int a) { ... }S(int a, int b) : S(a) { ... } // но нельзя продолжать список инициализации
S(const S&) = delete; // запретили генерировать метод копированияS() = default; // запросили сгенерировать метод
- Доступна только в структурах
S s{1, 2, 3, 4, "aaa"};
- Не принимает аргументов, поскольку вызывается, когда выходим из scope'а
- Генерируется компилятором всегда (пустой)
- Не надо самостоятельно вызывать деструктор (иначе UB)
- Можно только в том случае, когда дважды он точно не вызовется
- Syntax:
~Student() { ... }
- Конструкторы полей класса
- Конструктор класса
- Деструктор класса
- Деструктор полей класса
- Отношение "A - это друг B" не симметрично и не транзитивно
- Показатель плохого проектирования класса
#include <iostream>
// struct S;
// void bar();
class C {
private:
int foo(int x) { return x * x; }
friend struct S;
friend void bar();
};
struct S {
void foo() {
C c;
std::cout << c.foo(10) << '\n';
}
};
void bar() {
C c;
std::cout << c.foo(100) << '\n';
}
int main() {
S s;
s.foo();
bar();
}- Получается, конструкция
friendтак же является объявлением функции/класса.- Это, к слову, используется в Loophole'ах
- ADL - Argument Dependent Lookup
- Argument-dependent lookup (ADL), is the set of rules for looking up the unqualified function names in function-call expressions, including implicit function calls to overloaded operators. Source
- Simple def: collect names and choose a good one
std::vector<int> a = {0, 1};
swap(a[0], a[1]); // std::swapstd::cout << "Hello world"; // There is no operator<< in global namespace, but ADL examines std namespace because the left argument is in std and finds std::operator<<(std::ostream&, const char*)#include <iostream>
namespace A {
struct S {};
void foo(S) {
std::cout << "foo called\n";
}
}
int main() {
A::S s;
foo(s);
}#include <iostream>
class C {
friend int foo(C) { return 10; }
};
int main() {
// foo();
//::foo();
C c;
std::cout << foo(c) << '\n';
}==TODO== friend ADL SOF
- Статичные поля/методы являются являются общими для всего класса
struct S { static int x; };
int main() {
S::x; // = 0
}- Note: Можно вызывать статические методы из экземпляра таким же образом, как и из класса.
- Это позволяет изменять нестатические методы экземпляра на статические без необходимости обновления записи вызова функции.
struct Foo {
static void Bar() {}
};
int main() {
Foo f;
f.Bar(); // Вызовы эквивалентны
Foo::Bar();
}- Singleton - паттерн (антипаттерн - godobject - singleton, многое себе позволяющий)
struct Singleton {
static Singleton* Create() {
if (obj_ == nullptr) {
obj_ = new Singleton();
}
return obj_;
}
Singleton(const Singleton&) = delete;
private:
Singleton() { ... } // private
static Singleton* obj_;
};- Проверка на доступность осуществляется после выбора перегрузки
#include <iostream>
struct S {
void foo(int) { std::cout << "int\n"; }
private:
void foo(bool) { std::cout << "double\n"; }
};
int main() {
S s;
s.foo(3);
s.foo(true); // CE
}- Если класс такой, что вы определили нетривиальный конструктор, деструктор или оператор присваивания, то скорее всего, вам нужно реализовать все их.
- Правило трех это исключительно словесное правило, компилятор ему не следует