Try   HackMD

09 лекция - C++

(23.04.2022)

Про шаблоны

Это не функция! это пример как создать что-либо!

допустим есть a.h файл в котором мы реализуем функцию, и ещё b.h, b.cpp и main.cpp. Допустим мы подклюаем a.h в b.h и main.cpp, при линковке возникает ошибка

Про структуры в С++

В 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);
}
struct My
{
	int x;

	int myabs()
	{
		return abs(x);	// this->x (тоже самое)
		// this - это указатель на того, кто вызвал метод
	}
} a, b, c;


a.myabs();
b.myabs();

this передается как неявный аргумент метода, но в структуре не храниться!

методы создаеются с помощью name mangling, и они не принадлежат классу/структуре, мы лишь обьявляем, что они относятся к ним

struct My
{
	int x;

	int myabs()
	{
		return abs(x);	// this->x (тоже самое)
		// this - это указатель на того, кто вызвал метод
	}
}

const My z = {2};
z.myabs()		//не скомпилируется 
struct My
{
	int x;

	int myabs() const 	// обьявляет что this - указатель на константные данные 
	{
		return abs(x);	// this->x (тоже самое)
		// this - это указатель на того, кто вызвал метод
	}
}

const My z = {2};
z.myabs()		//скомпилируется 
struct My
{
	int x;

	int myabs(int x) {return this->x + x;}
	int myabs() const 	// обьявляет что this - указатель на константные данные 
	{
		return abs(x);	// this->x (тоже самое)
		// this - это указатель на того, кто вызвал метод
	}
}

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(); 	// тоже можно 

Про перегрузку операторов

Matrix a, b;
float c;

a.add(b);	// а хотелось бы a + b
a.add(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);
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)

My operator++(My &x) //++a
{

}


My operator++ (My &x, int)	//a++
//можем не указывать имя второму аргументу
//можем указать любой тип в качестве второго аргумента
{

}
My a, b, c;

(a+=b) += c; //хотитим поддерживать 

struct My
{
	My &operator+=(const My &b)
	{
		//...

		return *this;	// & съест * и разъименования на самом деле не произойдет
	}
}

В cout просто переопределили оператор <<

методы можно разделить на .h и .cpp my.h

struct My
{
	int x;
	int y;

	int myabs();	//обьявления
}

my.cpp

int My::myabs()	//реализация
{

}

методы реализованные в структуре рекомендуются компилятору как встраивымые (inline)

Про конструкторы/деструкторы

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;	//не скомпилируется
struct My
{
	int x;
	int y;

	My () : x(0), y(0);	//инициализация полей x, y
}

//My c(2);	//не скомпилируется
My z;		//c.x = 0, c.y = 0
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() {}	//деструктор, вызывается при уничтожениее обьекта, не принимает значений, нельзя перегрузить

Про выделение памяти в С++

int *p 		= new int(2);	//скалярный оператор
int *arr 	= new int[10];	//веторный оператор

//...

delete p;
delete[] arr;

new и delete вызывают конструкторы и деструкторы

Нет операций изменения размера (realloc)

Выделение памяти через malloc с конструкторами и деструкторами

My *p = (My *) malloc(sizeof(My));
//p->My(); 	//не скомпилируется
new(p) My(2, 3);	//placement new
//просто вызывает конструктор


p->~My();	//деструктор вызывать можно руками

free(p);

Проверка на невыделение

int *p = new int();	//не вернет NULL, бросит эксепшн

#include <new>
unsing namespace std;
int *p = new(nothrow) int; //вернет NULL

в var arg можно передать только double (float неявно приводиться к double)