- •Классы, Объекты и Методы
- •Struct DateStruct {
- •Int month;
- •Int year;
- •Методы классов
- •Void print () {
- •Int main () {
- •Int main () {
- •Int main () {
- •Спецификаторы доступа public и private
- •Int year; // открыто по умолчанию
- •Int main () {
- •Int main () {
- •Int main ()
- •Структуры. Классы
- •Инкапсуляция, Геттеры и Сеттеры Инкапсуляция
- •Int m_array[10];
- •Int main () {
- •IntArray array;
- •Void setValue(int index, int value) {
- •Функции доступа (геттеры и сеттеры)
- •Int m_month;
- •Int m_year;
- •Int main () {
- •Краткий обзор l-value и r-value
- •Инициализация ссылок
- •Ссылки в качестве параметров в функциях
- •Void changeN (int &ref) {
- •Int main () {
- •Int value1;
- •Int otherValue;
- •Ссылки. Указатели
- •Конструкторы
- •Int main () {
- •Конструкторы по умолчанию
- •Конструкторы с параметрами
- •Int m_numerator;
- •Int m_denominator;
- •Int getNumerator () {return m_numerator; }
- •Int getDenominator () {return m_denominator; }
- •Копирующая инициализация
- •Уменьшение количества конструкторов
- •Неявно генерируемый конструктор по умолчанию
- •Int main () {
- •Int main () {
- •Классы, содержащие другие классы
- •Int main() {
- •Список инициализации членов класса
- •Списки инициализации членов класса
- •Int m_value1;
- •Values() {
- •Int m_value1;
- •Инициализация массивов в классе
- •Инициализация переменных-членов, которые являются классами
- •Int main() {
- •Использование списков инициализации
- •Int m_value1;
- •Int m_value1;
- •Int m_value1;
- •Порядок выполнения в списке инициализации
- •Инициализация нестатических членов класса
- •Void print() {
- •Int main() {
- •Void print() {
- •Int main() {
- •Void print() {
- •Int main() {
- •Void print() {
- •Int main() {
- •Делегирующие конструкторы
- •Void DoX() {
- •Init();
- •Init();
- •Void Init()
- •Int main() {
- •Ещё о делегирующих конструкторах
- •Деструкторы
- •Имена деструкторов
- •Пример использования деструктора на практике
- •Выполнение конструкторов и деструкторов
- •Int getId() { return m_nId; }
- •Int main() {
- •Предупреждение о функции exit()
- •Скрытый указатель this
- •Скрытый указатель *this
- •Int m_number;
- •Int getNumber() { return m_number; }
- •Int main() {
- •Указатель this всегда указывает на текущий объект. Явное указание указателя this
- •Int data;
- •Цепочки методов класса
- •Заключение
Список инициализации членов класса
Рассмотрим, как инициализировать переменные-члены класса с помощью списка инициализации в языке С++, а также особенности и нюансы, которые при этом могут возникнуть.
1. Списки инициализации членов класса
2. uniform-инициализация в C++11
3. Инициализация массивов в классе
4. Инициализация переменных-членов, которые являются классами
5. Использование списков инициализации
6. Порядок выполнения в списке инициализации
7. Заключение
Списки инициализации членов класса
Мы инициализировали члены нашего класса в конструкторе
через оператор присваивания:
class Values {
private:
Int m_value1;
double m_value2;
char m_value3;
public:
Values() {
// Это всё операции присваивания, а не инициализация
m_value1 = 3;
m_value2 = 4.5;
m_value3 = 'd';
}
};
Сначала создаются m_value1, m_value2 и m_value3. Затем выполняется тело конструктора, где этим переменным присваиваются значения. Аналогичен код в не объектно-ориентированном C++:
Int m_value1;
double m_value2;
char m_value3;
m_value1 = 3;
m_value2 = 4.5;
m_value3 = 'd';
Хотя в плане синтаксиса языка C++ вопросов никаких нет — всё корректно, но более эффективно — использовать инициализацию, а не присваивание после объявления.
Для решения этой проблемы в C++ добавили метод инициализации переменных-членов класса через список инициализации членов, вместо присваивания им значений после объявления.
Из мы уже знаем, что инициализировать переменные можно тремя способами: через копирующую инициализацию, прямую инициализацию или uniform-инициализацию.
int value1 = 3; // копирующая инициализация
double value2(4.5); // прямая инициализация
char value3 {'d'} // uniform-инициализация
Использование списка инициализации почти идентично выполнению прямой инициализации (или uniform-инициализации).
Чтобы было понятнее, рассмотрим пример. Вот код с присваиванием значений переменным-членам класса в конструкторе:
class Values {
private:
int m_value1;
double m_value2;
char m_value3;
public:
Values() {
// Это всё операции присваивания, а не инициализация
m_value1 = 3;
m_value2 = 4.5;
m_value3 = 'd';
}
};
Теперь давайте перепишем этот код, но уже с использованием списка инициализации:
#include <iostream>
class Values {
private:
int m_value1;
double m_value2;
char m_value3;
public:
Values() : m_value1(3), m_value2(4.5), m_value3('d') // напрямую //инициализируем переменные-члены класса
{ // Нет необходимости использовать присваивание }
void print() {
std::cout << "Values(" << m_value1 << ", " << m_value2 << ", " << m_value3 << ")\n";
}
};
int main() {
Values value;
value.print();
return 0;
}
Результат выполнения программы:
Values(3, 4.5, d)
Список инициализации членов находится сразу же после параметров конструктора.
Он начинается с двоеточия (:), а затем значение для каждой переменной указывается в круглых скобках. Больше не нужно выполнять операции присваивания в теле конструктора.
Также обратите внимание, что список инициализации членов не заканчивается точкой с запятой.
Можно также добавить возможность передавать значения в конструктор для инициализации:
#include <iostream>
class Values {
private:
int m_value1;
double m_value2;
char m_value3;
public:
Values(int value1, double value2, char value3='d')
: m_value1(value1), m_value2(value2), m_value3(value3)
// напрямую инициализируем переменные-члены класса
{ // Нет необходимости использовать присваивание }
void print() {
std::cout << "Values(" << m_value1 << ", " << m_value2 << ", " << m_value3 << ")\n";
}
};
int main() {
Values value(3, 4.5); // value1 = 3, value2 = 4.5, value3 = 'd' (значение
// по умолчанию)
value.print();
return 0;
}
Результат выполнения программы:
Values(3, 4.5, d)
Мы можем использовать параметры по умолчанию для предоставления значений по умолчанию.
Например, класс, который имеет константную переменную-член:
class Values {
private:
const int m_value;
public:
Values(): m_value(7) // напрямую инициализируем константную
// переменную-член
{ }
};
Это работает, поскольку нам разрешено инициализировать константные переменные (но не присваивать им значения после объявления!).
Правило: Используйте списки инициализации членов, вместо операций присваивания, для инициализации переменных-членов вашего класса.
uniform-инициализация в C++11
В C++11 вместо прямой инициализации можно использовать uniform-инициализацию:
class Values {
private:
const int m_value;
public:
Values(): m_value { 7 } // используем uniform-инициализацию
{ }
};
Настоятельно рекомендуется использовать этот синтаксис (даже если вы не используете константы или ссылки в качестве переменных-членов вашего класса), поскольку списки инициализации членов необходимы при композиции и наследовании (это рассмотрим еще раз позже).
Правило: Используйте uniform-инициализацию вместо прямой инициализации в C++11.
