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
Другие вопросы по тегам