namespace
можно представлять как некую фамилию для переменной, функции, класса и т.д. По умолчанию все лежит в глобальном namespace.
Как задать свой namespace:
namespace hse {
void f() {
}
}
Чтобы обратиться к заданной выше f
, нужно написать:
hse::f();
Вместо этого можно добавить namespace в global namespace (но так делать не стоит, так как могут наложиться названия):
using namespace hse; // Не стоит так делать
f();
Вместо этого лучше добавлять в global namespace только нужные имена:
using std::vector; // Добавлять весь namespace std плохо, так как он займет большое количество имен
Namespace можно объявлять и внутри другого namespace. Таким образом, они будут образовывать дерево.
namespace hse {
namespace hse2 {
void f() {
}
}
}
hse::hse2::f();
Другой вариант обратиться к f()
:
using namespace hse;
hse2::f();
Обратиться к global namespace:
::f(); // Вызывает f из глобального namespace
Анонимный namespace - доступен только внутри данного cpp файла:
namespace {
}
Позволяет дать типу второе имя
using Numbers = std::vector<int>;
typedef std::vector<int> Numbers;
Полезно, чтобы определять длинные типы. При этом typedef
является устаревшией версией, в отличии от using
,
не поддерживает работу с шаблонами, поэтому всегда стоит использовать using
.
#define
просто подставляет вместо одного имени другое. Лучше не использовать, так как меньше защита от ошибок, чем при использовании using
.
Виды директив:
#pragma once // Следующее инструкция выполняется, только если уже не была выполнена в другом файле
#include <string> // По умолчанию можно случайно подключить одинаковые библиотеки, так как директива просто подставляет код
#ifndef
и #ifdef
позволяют создавать условия (например, подключать библиотеку, только если еще не подключена), но вместо них лучше использовать #pragma once
Классы стоит использовать, если кроме хранения данных в одном месте, требуется еще и логика работы с ними. Для просто хранения данных лучше использовать struct
.
В отличии от структуры, в классе все поля по умолчанию private
, то есть доступны только из этого класса (это их единственное отличие).
public:
- делает все дальше публичным, то есть доступным не только из класса(вплоть до конца класса или следующего слова из этих трех)private:
- делает все дальше приватным, то есть доступным только из самого классаprotected:
- делает все дальше доступным только из самого класса и из его наследниковКонструктор позволяет задавать состояние класса при создании (можно создавать конструкторы как с параметрами, так и без):
class Array {
public:
Array(size_t size) {
this->data = new int[size]();
this->size = size;
}
private:
int* data = nullptr; // Внутри класса эти поля можно использовать в любом порядке
size_t size = 0;
};
this
- внутри класса возвращает указатель на этот класс. Внутри константного метода возвращает константный указатель.
Ключевое слово explicit
- запрещает вызывать конструктор с неявным преобразование аргументов.
class Array {
public:
explicit Array(size_t size) {
}
};
default
конструктор - вызывается по умолчанию, задает всем полям базовые для их типов значения.
Если среди полей класса есть ссылка, нужно инициализировать ее с помощью следующего синтаксиса (аналогично для всех полей, которые должны быть инициализированны в теле конструктора):
class Array {
public:
explicit Array(std::string& word_argument) : word(word_argument) {
}
std::string& word;
};
const
методы - те, которые не меняют поля класса (для них все поля класса - const
). По умолчанию лучше делать все методы, которые не меняют поля класса, const
Внутри константного класса можно вызывать только const
методы.
Позволяет очистить поля класса и вызывать необходимые методы при уничтожении.
class Array {
public:
~Array() {
delete[] data; // Следить, чтобы data был валидным указателем (delete nullptr сработает, ничего не сделав)
}
private:
int* data;
};
Деструктор у класса только один и вызывается при уничтожении объекта.
void f() {
Array arr; // Вызывается пустой конструктор arr
} // Вызовется деструктор arr (статические объекты уничтожаются в конце main)
Статические функции вызываются не от объекта класса. Для них класс выполняет роль своебразного namespace.
class Array {
public:
static void Print() {
}
};
Вызвать статическую функцию:
Array::Print();
Статические функции могут обращаться к приватным полям класса:
class Array {
public:
static void Print(Array& const arr) {
std::cout << arr.size << std::endl;
}
private:
size_t size;
};