Найти в Дзене
osieman

С++ основы: ТИПЫ, ССЫЛКИ, КЛАССЫ, СПЕЦИАЛЬНЫЕ ФУНКЦИИ, ИНКАПСУЛЯЦИЯ, НАСЛЕДОВАНИЕ, КВАЛИФИКАТОРЫ, СПЕЦИФИКАТОРЫ, ПРИВЕДЕНИЕ, ШАБЛОНЫ

Оглавление

НАЧАЛО

В 1980-х. один из сотрудников фирмы At&T Bell Labs, совместив 2 языка Symula и C, получил С++. Его зовут Бьерн Страуструп.

ТИПЫ

Встроеные типы в C++ очень похожи на C:

  • символьные char, wchar_t (C++11: char16_t, char32_t)
  • целочисленные знаковые signed char, short int, штеlong int (C++11: long long)
  • целочисленные беззнаковые unsigned char, unsigned short int, unsigned int, unsigned long int (C++11: unsigned long long)
  • вещественные (с плавающей точкой) float, double, long double
  • логический bool (принимает значение false либо true)

ССЫЛКИ

Ссылка это всего-лишь еще одно имя для переменной.

До C++11 были только lvalue (Эль'Вэлью) ссылки, но после были добавлены и rvalue (Эр'Вэлью) ссылки.

Главное их различие:

  • lvalue - все, что имеет постоянное место в памяти (так же называют левыми - left hand side value)
  • rvalue - временный объект и живет до конца полного выражения (так же называют правыми - right hand side value)

На примере типа int объявляется следующим образом:

  • int& var_name - lvalue ссылка
  • int&& var_name - rvalue ссылка

Так как rvalue ссылки связываются с временным объектом, она может "провиснуть", ее никогда нельзя возвращать, как результат из функции.

Ссылка - это не указатель, указатель имеет место в памяти, в том время, как сама ссылка, нигде не хранится. Но в некоторых случаях, неявно, она может стать указателем для передачи в функцию.

КЛАССЫ

Одной из основных задач классов является разделение ИНТЕРФЕЙСА и КОНТЕКСТА.

ИНТЕРФЕЙС - как правило, чисто абстрактный (имеет только объявление методов, но не определяет их) класс, цель которого служить шаблоном для других, более частных объектов.

КОНТЕКСТ - класс, который наследуется от интерфейса, определяя каждый метод, в котором производит проверку перед началом и в конце каждого метода на сохранение инвариантов класса.

Ярким примеров в C++ такого разделения есть в самой стандартной библиотеке языка, КОНТЕЙНЕР (container) - является более общим понятием, которое описывает некий стандарт для всех дочерних объектов. А уже его реализации ВЕКТОР (vector), ЛИСТ (list) и ДЕК (deque), описывают каждый сам для себя, что будет делать каждый из методов, который продиктовал им их общий интерфейс. Эта концепция позволяет нам использовать вектор, который является динамическим массивом и лист, он же двусвязный список, как полностью взаимозаменяемые.

В C++ есть 3 вида классов:

  • класс - объявляется через ключевое слово class и является классическим классом.
  • структура - объявляется через ключевое слово struct, является таким же классом, но при отсутствии модификатора доступа private или public все члены будут иметь иметь public доступ, в то время как в class будет pivate.
  • объединение - объявляется через ключевое слово union, все поля класса будут ссылаться на один и тот же адрес в памяти, можно использовать когда нужно иметь разную по типу интерпретацию. Размер выделяемой памяти определяется по большему из них.

пример union

union A {
int x,y,z;
std::vector<int> vec;
};

отсюда

vec[0] == x
vec[1] == y
vec[2] == z

СПЕЦИАЛЬНЫЕ ФУНКЦИИ

Классы имеют ряд специальных функций

  • Конструктор по умолчанию - вызывается при создании объекта (при вызове new).
  • Деструктор - в момент завершения полного выражения, вызывается для уничтожения объекта.
  • Конструктор копирования - инициализировать объект можно и передав другой объект этого же типа, при этом в новый объект будут скопированы значения полей переданного.
  • Конструктор перемещения - аналогично копированию, только поля оригинального объекта будут обнулены.
  • Оператор присваивания копированием - оператор = для lvalue объекта.
  • Оператор присваивания перемещением - оператор = для rvalue объекта.

Как правило они не требуют определения, так как принцип единой ответственности (Single Responsibility Principle) гласит о том, что у каждого объекта должна быть лишь одна задача, спец. функции определяются только для тех объектов, задача которых заключается в управлении собственной памятью.

Нужно помнить правило "пяти" - если вам нужно нетривиально определить один из них, то вам нужно определить все пять.

ВНИМАНИЕ!!! Если у Вас в классе есть хотя бы один виртуальный метод (то есть тот, который при наследовании требует переопределения - override), то вам нужно сделать и деструктор виртуальным (он может быть пустым), чтобы удалять объекты производного класса по указателю на базовый класс.

НАСЛЕДОВАНИЕ

Наследование это процесс, в результате которого, новый объект получает все поля родительских...

С++ поддерживает множественное наследование, то есть мы может создать новый класс, затащив в него поля сразу от 2-х и более классов предков.

ИНКАПСУЛЯЦИЯ

Инкапсуляция защищает инварианты (условия, которые выполняются все время жизни объекта) класса. То есть инкапсуляция - это про доступ к именам. Нужно запомнить три модификатора:

  • public - поле имеет публичный доступ на всех уровнях.
  • private - поле имеет приватный доступ, то есть доступно только внутри функций самого класса.
  • protected - похоже на private модификатор, но будет так же доступно при наследовании в дочерних объектах.

КВАЛИФИКАТОРЫ

В языке есть 2 квалификатора для переменных:

  • const - переменная не доступна для изменения ее значения.
  • volatile - подсказка компилятору о том, что переменная может в любой момент непредсказуемо измениться (применяется для отмены оптимизаций над переменной).

СПЕЦИФИКАТОРЫ

Так же есть спецификатор для функций:

  • inline - подсказка компилятору, чтобы тот встроил тело функции прямо в код, вместо вызова ее, что позволяет повысить производительность.

Функция, определенная внутри тела класса, будет inline по умолчанию.

ПРИВЕДЕНИЕ

Приведение, по сравнению с языком C, в C++ чуть сложнее:

  • C-style cast - приведение в стиле C, отсутствуют какие-либо ограничения и проверки (в C++ стараются не использовать, его тяжело искать в коде и в целом менее прогнозируемый).
  • static_cast - приведение с проверкой типов на этапе компиляции.
  • dynamic_cast - приведение на этапе исполнения, считается более безопасным, чем static_cast, но несет издержки, поскольку выполняется во время работы программы.
  • const_cast - меняет статус CV, может добавить или убрать const и volatile.
  • reinterpret_cast - приведение для абсолютно несовместимых типов, его применение считается небезопасным.

ШАБЛОНЫ

C++ вводит еще одно новшество - шаблоны. Шаблоны похожи на макросы, но в отличии от оных, при использовании шаблонов, Вы получаете полноценную проверку, лексически и синтаксически, компилятором.

Применяется, чтобы минимизировать трудозатраты для реализации одной логики для разных типов, компилятор подставит типы и реализует нужные функции самостоятельно.

Чтобы объявить шаблон, нужно просто указать перед объявлением класса или функции template <typename T>, где T - имя для типа, может быть любым, далее можно использовать как самый обычный тип данных. При компиляции будет подставлен параметризованный тип.

ИТЕРАТОРЫ

Итератор - это объект, который может перебирать элементы в контейнере и предоставлять доступ к отдельным элементам.

Простым инкрементом можно идти от одного элемента к другому, нужно помнить, что ++var эффективнее var++, так как во втором случае помимо увеличения значения происходит возврат старого, то есть дополнительное копирование.

Основным преимуществом является возможность передачи его без копирования объекта, в котором идет перебор элементов.

АББРЕВИАТУРЫ

  • UB - Undefined Behaviour (Неопределенное поведение)
  • RAII - Resource Acquisition Is Initialisation (Захват ресурса - это инициализация)
  • SRP - Single Responsibility Principle (Принцип единой ответственности).
  • SFINAE - Substitution Failure Is Not An Error (Неудачная подстановка - не ошибка)
  • RTTI - Run-Time Type Information (Идентификация типа во время исполнения)

ПОЧЕМУ C++ НЕ ЗАМЕНИЛ C?!

В момент компиляции имя функции или переменной в C не меняется, а именно их метка в ассемблере, то есть соблюдается гарантия по именам, в то время как в C++ происходит манглирование (процесс искажения имен) метки зависящее от типа и каждый компилятор реализует это самое манглирование на собственное усмотрение, так как это не стандартизовано. В результате метки из разных компиляторов для одного кода будут разными.

Манглирование дало возможность ввести перегрузку функций, поля для классов, шаблоны, но лишило возможности создавать интерфейсы, которые бы могли взаимодействовать друг с другом, для этих целей все еще используется C.

Но, в С++ все же есть возможность отказаться от манглирования, дабы согласовать API, указав extern "C" до объявления переменной или фукнции.

Наука
7 млн интересуются