# 09 лекция - C++ (23.04.2022) ## Про шаблоны > Это не функция! это пример как создать что-либо! допустим есть a.h файл в котором мы реализуем функцию, и ещё b.h, b.cpp и main.cpp. Допустим мы подклюаем a.h в b.h и main.cpp, при линковке возникает ошибка ## Про структуры в С++ В C++ в структурах можно реализовывать функции (методы) ```c++ struct My { int x; } a, b, c int myabs (My a) // копирует всю структуру { return abs(a.x); } int myabs (My *a) // норм { return abs(a->x); } int myabs (const My &a) // лучший вариант, но не бесплатный, тк лишнее обращение в память (про ссылку) { return abs(a.x); } ``` ```c++ struct My { int x; int myabs() { return abs(x); // this->x (тоже самое) // this - это указатель на того, кто вызвал метод } } a, b, c; a.myabs(); b.myabs(); ``` > this передается как неявный аргумент метода, но в структуре не храниться! > методы создаеются с помощью name mangling, и они не принадлежат классу/структуре, мы лишь обьявляем, что они относятся к ним ```c++ struct My { int x; int myabs() { return abs(x); // this->x (тоже самое) // this - это указатель на того, кто вызвал метод } } const My z = {2}; z.myabs() //не скомпилируется ``` ```c++ struct My { int x; int myabs() const // обьявляет что this - указатель на константные данные { return abs(x); // this->x (тоже самое) // this - это указатель на того, кто вызвал метод } } const My z = {2}; z.myabs() //скомпилируется ``` ```c++ struct My { int x; int myabs(int x) {return this->x + x;} int myabs() const // обьявляет что this - указатель на константные данные { return abs(x); // this->x (тоже самое) // this - это указатель на того, кто вызвал метод } } ``` ```c++ struct My { int x; // рекумедуется называть как m_ (m_x), (как глобальные переменные называть начиная с g_) static int y; // одна на все структуры такого типа переменная, но видно внутри структуры // не создает y, надо в одном .cpp в глобальной области сказать // int My::y; static int f() {return 2;} // не получает this, но принадлежит только к структуре int myabs() const { return abs(x); } } My::y = 3; // к статическим полям можно оращаться без имени обьескта, а по имени типа My::f(); // тоже можно ``` ## Про перегрузку операторов ```c++ Matrix a, b; float c; a.add(b); // а хотелось бы a + b a.add(c); ``` ```c++ My operator+(const My &a, const My &b) //обычная функция (внешняя форма) // & тк мы не хотим создавать копию // const чтобы складывалить и константные структуры a + My{5}, например { My res; res.x = a.x + b.x; res.y = a.y + b.y; return res; } c = a + b; //c = operator+(a, b); ``` ```c++ struct My { int x; int y; My operator+(const My &b) const //метод класса (внутренняя форма) //const после обьявления чтобы не менять текущий класс // & тк мы не хотим создавать копию // const в аргументах чтобы складывалить и константные структуры a + My{5}, например { My res; res.x = x + b.x; // (this.x + b.x) res.y = y + b.y; // (this.y + b.y) return res; } } c = a + b; //c = operator+(a, b); ``` > оператор стандартный тип + структура возможно только во внешней форме > оператор = только во внутренней форме ### Ещё про операторы ``` operator(); //можно перегрузить оператор () и [] operator[]; My a; a(); a[]; ``` Про операторы - `&&` и `||` вычисляется сокращенно, но их тоже можно перегрузить и не будет сокращенного вычисления, тк это уже функции, а не операторы > сокращенное вычисление - если мы знаем про тип выражения без второго аргумента, то он не будет вычислен > напрмер, `if(p != NULL && p->x)` ```c++ My operator++(My &x) //++a { } My operator++ (My &x, int) //a++ //можем не указывать имя второму аргументу //можем указать любой тип в качестве второго аргумента { } ``` ```c++ My a, b, c; (a+=b) += c; //хотитим поддерживать struct My { My &operator+=(const My &b) { //... return *this; // & съест * и разъименования на самом деле не произойдет } } ``` > В `cout` просто переопределили оператор `<<` > методы можно разделить на `.h` и `.cpp` `my.h` ```c++ struct My { int x; int y; int myabs(); //обьявления } ``` `my.cpp` ```c++ int My::myabs() //реализация { } ``` > методы реализованные в структуре рекомендуются компилятору как встраивымые (`inline`) ## Про конструкторы/деструкторы ```c++ struct My { int x; int y; My (int a, int b = 0) {x = a; y = b}; // присвоение полям x, y //My (const My &a) //есть по умолчанию } My c(2); //c.x=2, c.y = 0 //My z; //не скомпилируется ``` ```c++ struct My { int x; int y; My () : x(0), y(0); //инициализация полей x, y } //My c(2); //не скомпилируется My z; //c.x = 0, c.y = 0 ``` ```c++ struct My { int x; int y; My (int a=1, int b = 0) : x(a), y(b); //инициализация полей x, y } My c(2); //c.x = 2, c.y = 0 My z; //c.x = 0, c.y = 0 My z(); //ЭТО ПРОТОТИП ФУНКЦИИ My z{}; //17 стандарт тоже самое My z; My z = (); //ЭТО КОНСТРУКТОР int x(2); //можно теперь писать, вызов конструктора int ``` ``` ~My() {} //деструктор, вызывается при уничтожениее обьекта, не принимает значений, нельзя перегрузить ``` ## Про выделение памяти в С++ ```c++ int *p = new int(2); //скалярный оператор int *arr = new int[10]; //веторный оператор //... delete p; delete[] arr; ``` > `new` и `delete` вызывают конструкторы и деструкторы > Нет операций изменения размера (`realloc`) Выделение памяти через malloc с конструкторами и деструкторами ```c++ My *p = (My *) malloc(sizeof(My)); //p->My(); //не скомпилируется new(p) My(2, 3); //placement new //просто вызывает конструктор p->~My(); //деструктор вызывать можно руками free(p); ``` Проверка на невыделение ```c++ int *p = new int(); //не вернет NULL, бросит эксепшн #include <new> unsing namespace std; int *p = new(nothrow) int; //вернет NULL ``` > в var arg можно передать только double (float неявно приводиться к double)