Проблемы заказа инициализации
-
26-10-2019 - |
Вопрос
Учитывая пример кода:
class B {
//Some contents.
};
class C {
private:
B& b;
};
class A {
private:
B b;
C c;
};
У класса C есть ссылка на AB, поэтому его необходимо инициализироваться вместе с ним. Класс A содержит экземпляр B и экземпляр C.
Мой вопрос: могу ли я инициализировать экземпляр C в экземпляре B в экземпляре B в (при условии, что я потрудился поставить конструкторы)? Во -вторых, нужно ли мне выполнить какую -либо явную инициализацию B в A, или это по умолчанию инициализируется, поскольку его тип класса в классе?
Решение
Переменные члена инициализируются в том порядке, в котором они объявлены в объявлении класса (Даже если у вас есть их в другом порядке в списке инициализации конструктора), так что да, к тому времени c
инициализируется, b
будет инициализирован, и вы можете использовать b
инициализировать c
.
Как отмечает Рикардо Карден, это все равно будет работать, даже если вы объявите c
до b
в определении класса (что означает, что вы пройдете C::C
ссылка на ненициализированную B
) однако вы вызываете неопределенное поведение, если вы использовать объект внутри C::C
. Анкет Безопаснее объявить b
Во -первых, потому что, хотя вы не можете использовать b
внутри C::C
Теперь вы могли бы в будущем и забыть, что ссылка относится к ненициализированной B
, и вызвать UB.
И нет, вам не нужно явно инициализировать b
(Если это не Капсул) Если вы не хотите, чтобы это было по умолчанию. Так что этот код был бы тем, что вы хотите (опять же, если B
не POD):
A::A() : c(b) { }
Другие советы
На ваш первый вопрос: вы можете инициализировать его, написав такие конструкторы:
C::C(B& bInst): b(bInst){}
A::A():b(), c(b) {}
Конечно, если ваш конструктор C
на самом деле использует b
(вместо его адреса) вам необходимо убедиться, что заказ инициализации остается прежним, поэтому b
должен быть объявлен до c
, поскольку участники инициализируются в порядке, в котором они объявлены (даже если список инициализатона помещает их в другой заказ).
И нет, вам не нужно явно инициализировать B, так как он будет по умолчанию, если вы этого не сделаете. Конечно, если B является POD, это означает, что он остается ненициализированным (при явном инициализации его с помощью b()
В списке инициализаторов A()
инициализировал его 0
).
Могу ли я инициализировать экземпляр C в экземпляре B с экземпляром B в (при условии, что я потрудился поставить конструкторы)
Конечно.
Во -вторых, нужно ли мне выполнить какую -либо явную инициализацию B в A, или это по умолчанию инициализируется, поскольку его тип класса в классе?
Нет, это нормально.
Да, поскольку C содержит только ссылку на B, а не отдельный экземпляр, вы можете поместить конструктор в C и позволить справочнику ACB AB
B и C внутри A оба создаются/построены автоматически при создании экземпляра A.