Использование списков инициализаторов с унаследованными переменными - PullRequest
4 голосов
/ 11 июня 2011

Я около 20 минут возился с программой и обнаружил, что по какой-то причине она не позволяет мне использовать унаследованные переменные в списках инициализации. Эта программа, например:

class A {
protected:
        int i;
};

class B : public A {
public:
        B() : i(45) { }
};

int main() {
        B b;
}

выдаст ошибку

ошибка: в классе "B" нет поля с именем "i"

Однако, если вы измените конструктор на это:

B() { i = 45; }

Компилируется.

Я никогда не знал, что вы не можете инициализировать унаследованные переменные. У меня вопрос, почему?

Ответы [ 3 ]

10 голосов
/ 11 июня 2011

Объект может быть инициализирован только один раз: когда он впервые появляется.

A инициализирует все свои переменные-члены в своем конструкторе (до выполнения тела его конструктора).Таким образом, B не может инициализировать переменную-член A, поскольку переменная-член уже была инициализирована конструктором A.

(В данном конкретном случае технически i остается неинициализированным, поскольку A не инициализировал его; при этом ответственность за инициализацию переменных-членов по-прежнему лежит на A.)

4 голосов
/ 11 июня 2011

Вы не можете сделать это в C ++. Обычным способом является наличие (protected) конструктора в родительском классе, который принимает параметр, используемый для установки переменной.

Использование таких защищенных атрибутов почти никогда не предлагается, поскольку это позволяет дочерним классам нарушать инварианты родительских классов, что в дальнейшем только вызывает серьезные отладочные головные боли.

2 голосов
/ 11 июня 2011

Вы должны определить публичный конструктор с параметром в классе A. Затем в классе B использовать конструктор из базового класса. Пример:

#include <iostream>
using namespace std;

class A {
protected:
    int i;
public:
    A(int number) : i(number) {}
};

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

int main() {
    B b;
}
...