Стандарт С++11: частичный обзор новелл
дата публикации: 2016-10-31

Стандарт С++11 дополнил список зарезервированных слов новыми и расширил функционал некоторых существующих. Итак, рассмотрим все по списку.

1. Замещение виртуальных функций.

Во избежании ошибок в коде при переопределении виртуальных методов в классе наследнике существует дополнительное зарезервированное слово override. Пример кода:

class Base {
  virtual void function();
};

class Derived : public Base {
  void funktion();
  void fanction() override;
  void function() override;
};

Данный код не запустится, так как компилятор выдаст ошибку. Дело в том, что компилятор при определении метода funktion() не проверяет на возможность замещения им существующего виртуального метода в родительском классе, а если мы дополнительно указываем override, как в случае с fanction() проверка осуществляется и выдается ошибка (ввиду несоответствия имени виртуальной функции базового класса, а попросту банальной ошибки). Понятно, что в случае function() override ошибки нет, так как тут все верно. Такое дополнение снимает ответственность с плеч программиста и перекладывает ее на компилятор.

2. Финальность методов и классов.

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

class Base {
  virtual void function() final;
};

class Derived1 final: public Base {
  void function();
};

class Derived2: public Derived1 {
};

В этом коде будет сразу две ошибки: ошибка первая - невозможность переопределения final метода function() в классе наследнике Derived1, ошибка вторая - невозможность наследования класса Derived2, так как класс Derived1 определен как final.

3. Методы по умолчанию, запрет.

При инстанцировании класса создаются ряд методов автоматически. Для того, чтобы в дальнейшем точно знать какие методы будут использованы, а какие запрещены, применяются зарезервированные слова default и delete. Пример кода:

class Array {
  int nArr, *pArr;
public:
  Array() = default;
  ~Array();
  Array(const int* pArr, const int nArr);
  Array(const Array& obj) = delete;
  Array& operator=(const Array& obj) = delete;
  Array(Array&& obj);
  Array& operator=(Array&& obj);
};

В этом коде для экземпляра класса запрещен конструктор копирования и оператор копирования, зато открыт конструктор перемещения и оператор перемещения, конструктор Array() не имеет реализации и определен по умолчанию.

4. Обобщенные константные выражения.

Для определения константной функции или константного значения ранее использовалось обозначение const. Однако стандарт С++11 расширяет понятие констант и теперь они могут быть определены для не целочисленных типов тоже, кроме того, constexpr позволяет на этапе компиляции вычислить значения некоторых методов и уже в дальнейшем использовать константные выражения вместо них. Пример кода:

constexpr int function(int i, int j) {
  return (i > j) ? i : j;
}

int main() {
  int arr[function(1,2) + 12];
  return 0;
}

В коде рассматривается пример использования constexpr в качестве спецификатора для функции, возвращающей значение, в дальнейшем используемое в подсчете выделяемой памяти под массив.

5. Константа нулевого указателя.

В общем-то 0 это не пустота, это тоже определенное значение возможно типа int. С точки зрения логики должна существовать пустота, причем пустота для каждого типа своя, таким образом в стандарте было предложено использовать значение nullptr, которое для разных типов указателей неявно приводится к соответствующему типу. Пример использования:

char *pc = nullptr;
int  *pi = nullptr;

6. Операторы явного преобразования.

Вообще говоря explicit достаточно часто используется в конструкторах, приведу следующий пример:

class A {
  int a;
public:
  explicit A(int a);
  explicit operator int();
};

A::A(int a) {
  this->a = a;
}

A::operator int() {
  return a;
}

int main() {
  A obj1(2); // исполняется всегда
  A obj2 = 2; // исполняется только если explicit конструктора закомментировано
  int x = obj1; // исполняется только если explicit оператора закомментировано
  return 0;
}

В примере будет сгенерирована ошибка в случае A obj2 = 2, ввиду того, что explicit при определении конструктора запрещает неявное преобразование выражения A obj2 = 2 в выражение A obj1(2). В стандарте С++11 explicit становится доступным еще и для операторов преобразования типа. В вышеприведенном коде будет ошибка в строке int x = obj1, так как неявное преобразование запрещено.