C++: инициализация унаследованного поля
У меня есть вопрос об инициализации унаследованных членов в конструкторе производного класса. Пример кода:
class A
{
public:
int m_int;
};
class B: public A
{
public:
B():m_int(0){}
};
Этот код дает мне следующий вывод:
In constructor 'B::B()':
Line 10: error: class 'B' does not have any field named 'm_int'
(см. http://codepad.org/tn1weFFP)
Я догадываюсь, почему это происходит? m_int
должен быть членом B
и родительский класс A
должен быть уже инициализирован при инициализации m_int
в B
происходит (потому что родительские конструкторы запускаются до инициализации члена унаследованного класса). Где ошибка в моих рассуждениях? Что на самом деле происходит в этом коде?
EDIT
Я знаю о других возможностях инициализации этого члена (базовый конструктор или присваивание в производном конструкторе), но я хочу понять, почему это не так, как я пытаюсь? Какая-то особенность языка С ++ или что-то подобное? Пожалуйста, укажите мне параграф в стандарте C++, если это возможно.
5 ответов
Вам нужно создать конструктор для A (он может быть защищен, так что только B может вызывать его), который инициализирует m_int так же, как вы, затем вызываете :A(0)
где у вас есть :m_int(0)
Вы также можете просто установить m_int = 0
в теле конструктора Б. Он доступен (как вы описываете), но не доступен в специальном синтаксисе конструктора.
Для того, чтобы построить экземпляр класса B
вы сначала создаете экземпляр класса A
, Во время этого экземпляра m_int
инициализируется. После этой инициализации b
называется конструктор, поэтому вы не можете повторно инициализировать m_int
, Если это ваша цель, то вы можете реализовать конструктор для A
который принимает Int, а затем вызвать это в B
Список инициализации:
class A
{
public:
A(int x): m_int(x) {}
int m_int;
};
class B: public A
{
public:
B(): A(2) {}
};
То, что вы хотите, это:
class A{
public:
A() : m_int(0);
int m_int;
};
чтобы m_int
инициализируется в правильном месте.
Редактировать:
Из приведенного выше комментария причина, по которой компилятор жалуется, когда вы пытаетесь инициализировать m_int
переменная в B
является то, что он уже был инициализирован конструктором A
, То есть вы не можете повторно инициализировать что-либо, только переназначить. Таким образом, вы можете переназначить, как сказал Бен Джексон, или инициализировать в нужном месте.
Сделать конструктор в A и использовать B(): A(2) {} застрахован от B():m_int(0){} его работа.
Используйте первое предложение Бена Джексона. Второй вариант (т.е. установка m_int = 0 в теле конструктора) допустим, если m_int не является константой. Я считаю, что это не сработало бы, если бы m_int было константой (но первое предложение было бы), что я бы рекомендовал, если вы не собираетесь делать изменяемым.
Ну действуй:
class A {
protected:
A():m_int{0}{} // Move constructor to parent class
public:
const int m_int;
auto print() {std::cout << m_int << std::endl;} // For example
};
class B: virtual public A {
public:
B():A(){}
};
Пример:
auto x {B()};
x.print() // Prints 0