Инициализация защищенных членов родителя с помощью списка инициализации (C++)

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

Пример кода:

class Parent
{
protected:
    std::string something;
};

class Child : public Parent
{
private:
    Child() : something("Hello, World!")
    {
    }
};

Когда я пытаюсь это сделать, компилятор говорит мне: "В классе" Child "нет поля с именем" что-то "". Возможно ли что-то подобное? Если так, какой синтаксис?

Большое спасибо!

5 ответов

Решение

Это невозможно, как вы описываете. Вам нужно будет добавить конструктор (может быть защищен) в базовый класс, чтобы переслать его. Что-то вроде:

class Parent
{
protected:
    Parent( const std::string& something ) : something( something )
    {}

    std::string something;
}

class Child : public Parent
{
private:
    Child() : Parent("Hello, World!")
    {
    }
}

Когда компилятор находит список инициализаторов, объект производного класса еще не сформирован. Конструктор базового класса до этого не вызывался. Только после вызова конструктора базового класса something приходит к бытию. Отсюда и проблема. Когда вы не вызываете конструктор базового класса явно, компилятор делает это за вас (генерируя соответствующий тривиальный конструктор для базового класса). Это вызывает something элемент по умолчанию инициализирован.

Из C++0x черновик:

12.6.2 Инициализация баз и членов

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

Примечание: Акцент мой.

Вы не можете инициализировать членов родительского класса в списке инициализации конструктора производного класса. Неважно, являются ли они защищенными, публичными или чем-то еще.

В вашем примере член something является членом Parent класс, что означает, что он может быть инициализирован только в списке инициализатора конструктора Parent учебный класс.

Как сказал @philsquared, вы не можете инициализировать члены родительского класса из списка инициализации членов дочернего элемента, но вы можете добавить конструктор родительского класса и вызвать этот конструктор из списка инициализации членов дочернего элемента.

И, как сказал @dirkgently, причина, по которой вы не можете инициализировать члены родительского класса в списке инициализации, заключается в том, что на данный момент конструктор родительского класса еще не вызван, поэтому эти поля недоступны.

Для потомков я также хотел указать, что если вы не хотите писать конструктор для своего родительского класса, вы можете просто инициализировать защищенные члены в теле конструктора:

      class Child : public Parent
{
private:
    Child() {
        something = "Hello, World!";
    }
};

Может быть, вы можете попробовать это таким образом, используя ключевое слово "использование"

class Parent
{

protected:
std::string something;
};

class Child : public Parent
{

private:
using Parent::something;
Child()
{
    something="Hello, World!";
}
};
Другие вопросы по тегам