Проблемы с порядком инициализации - PullRequest
3 голосов
/ 10 января 2012

Приведенный пример кода:

class B {
    //Some contents.
};

class C {
    private:
        B& b;
};

class A {
    private:
        B b;
        C c;
};

Класс C имеет ссылку на a b, поэтому его необходимо инициализировать вместе с ним. Класс A содержит экземпляр B и экземпляр C.

Мой вопрос: могу ли я инициализировать экземпляр C в A с экземпляром B в A (при условии, что я потрудился поместить конструкторы)? Во-вторых, мне нужно выполнить какую-либо явную инициализацию B в A, или это инициализируется по умолчанию, поскольку это тип класса внутри класса?

Ответы [ 4 ]

6 голосов
/ 10 января 2012

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

Как отмечает Рикардо Карденес, он все равно будет работать, даже если вы объявите c до b в определении класса (что означает, что вы передадите C::C ссылку на неинициализированный B), однако вы вызываете неопределенное поведение если вы используете объект внутри C::C. Сначала безопаснее объявить b, потому что, хотя вы не можете использовать b внутри C::C сейчас, вы можете в будущем забыть, что ссылка относится к неинициализированному B и вызывает UB.

И нет, вам не нужно явно инициализировать b (если это не POD ), если вы не хотите, чтобы он создавался по умолчанию. Так что этот код будет тем, что вы хотите (опять же, если B не POD):

A::A() : c(b) { }
3 голосов
/ 10 января 2012

На ваш первый вопрос: вы можете инициализировать его, написав конструкторы следующим образом:

C::C(B& bInst): b(bInst){}
A::A():b(), c(b) {}

Конечно, если ваш конструктор C фактически использует b (а не только его адрес), вынеобходимо убедиться, что порядок инициализации остается прежним, поэтому b должен быть объявлен до c, поскольку члены инициализируются в том порядке, в котором они объявлены (даже если список инициализации помещает их в другой порядок).

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

0 голосов
/ 10 января 2012

Могу ли я инициализировать экземпляр C в A с экземпляром B в A (при условии, что я потрудился поместить конструкторы)

Конечно.

Во-вторых, мне нужно выполнить какую-либо явную инициализацию B в A, или она инициализируется по умолчанию, поскольку это тип класса внутри класса?

Нет, все в порядке.

0 голосов
/ 10 января 2012

Да, поскольку C содержит только ссылку на B, а не отдельный экземпляр, вы можете поместить конструктор в C и позволить A.C.b ссылаться на A.B.

B и C внутри A создаются и создаются автоматически при создании экземпляра A.

...