Инициализация членов базового класса - PullRequest
1 голос
/ 28 марта 2020

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

class A { 
public:
   int x;
};

class B : public A {
public:
    B() : x(0) {} // error
};

, в то время как следующее:

class A { 
public:
   int x;
};

class B : public A {
public:
    B() { x = 0; } // ok
};

Ответы [ 2 ]

2 голосов
/ 28 марта 2020

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

Вы можете изобразить свой объект типа B следующим образом:

class C {
public:
    A parent;
};

В этом примере вы не смог бы инициализировать parent.x, но только parent. Даже если вы можете получить доступ и изменить parent.x в теле, как вы это сделали, вы не сможете получить доступ к его элементам в списке инициализатора:

C::C() {
    parent.x = 5; // Works
}

C::C() : parent.x(5) {} // Won't work

И с другой стороны, если у вас был конструктор для A как

A::A(int i): x(i) {}

, вы можете использовать этот конструктор в списке инициализаторов для C:

C::C(): parent(5) {} // Works and does what you want

У вас есть та же опция для B, при условии, что у вас есть конструктор для A:

B::B(): A(5) {}
1 голос
/ 28 марта 2020

Этот фрагмент кода

class A { 
public:
   int x;
};

class B : public A {
public:
    B() : x(0) {} // error
};

является неправильным, поскольку в соответствии со стандартом C ++ (12.6.2 Инициализация баз и членов)

2 В идентификаторе mem-initializer-id начальный неквалифицированный идентификатор ищется в области видимости класса конструктора и, если не найден в этой области видимости, он ищется в области видимости, содержащей определение конструктора. [Примечание: если класс конструктора содержит член с тем же именем, что и у прямого или виртуального базового класса класса, mem-initializer-id, именующий элемент или базовый класс и состоящий из одного идентификатора, ссылается на член класса. Mem-initializer-id для скрытого базового класса может быть указан с использованием квалифицированного имени. - примечание конца] Если только mem-initializer-id не присваивает имя классу конструктора, элементу данных non-stati c класса конструктора или прямой или виртуальной базе этого класса, mem-initializer является недействительным Formed.

Вместо этого вы можете написать

class A { 
public:
   int x;
};

class B : public A {
public:
    B() : A{ 0 } {}
};

, где в mem-initializer-list используется прямой идентификатор базового класса.

Обратите внимание на что вместо скобок используются скобки A{ 0 }, поскольку class A является агрегатом.

В этом фрагменте кода

class A { 
public:
   int x;
};

class B : public A {
public:
    B() { x = 0; } // ok
};

Элемент данных x отсутствует в mem-initializer-list и назначается в теле конструктора после инициализации по умолчанию. То есть в теле конструктора используется оператор присваивания для уже созданного объекта.

...