Инициализация защищенных членов родителя с помощью списка инициализации (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!";
}
};