Использовать адрес / указатель суперкласса в списке инициализации - PullRequest
3 голосов
/ 12 апреля 2010

контекст 1: класс D: общедоступный B1, общедоступный B2 {};

контекст 2: B2 берет B1 для инициализации: B2 (B1 *) // Конструктор B2

мой вопрос в списке инициализации D:

D :: D (): B1 (), B2 (?) ... Что должно быть в?

Я не хочу помещать "(B1 *) это" в? место, потому что не стоит использовать «это» в списке инициализации. А поскольку часть B1 инициализирована, имеет смысл использовать ее.

Что мне делать?

Ответы [ 2 ]

3 голосов
/ 12 апреля 2010

Можно использовать B1 часть this, потому что она уже инициализирована. §12.6.2 / 5: «прямые базовые классы должны быть инициализированы в порядке объявления, как они появляются в списке базовых спецификаторов (независимо от порядка mem-initializer).»

Список базовых спецификаторов здесь равен class D : public B1, public B2, а список mem-initializer-list равен D::D() : B1(), B2( … ).

Я бы сказал, что это имеет "кодовый запах".

РЕДАКТИРОВАТЬ: Теперь я понимаю вашу озабоченность, является ли this неопределенным вне тела конструктора, который не включает инициализаторы членов. Язык, позволяющий это, скрыт между двумя примерами, и я сначала его пропустил. Пункт 7: «Имена в списке выражений mem-инициализатора оцениваются в области действия конструктора, для которого задан mem-initializer. "

Если B2 действительно нужно сохранить указатель на B1, и этот указатель всегда будет указывать внутри самого производного объекта, рассмотрим виртуальное наследование.

class B1 {};
class B2 : virtual B1 {}; // under the hood, B2 has a pointer to B1.
class D : public virtual B1, public B2 {}; // D has a pointer too
 // Only the most-derived class (the one actually used for instantiation)
 // implements space for and initialization of the B1.
1 голос
/ 12 апреля 2010

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

Я бы внимательно посмотрел на этот дизайн - возможно ли изменить его, чтобы сделать это ненужным? Можете ли вы переместить вещи в члены для инкапсуляции, а не наследования - действительно ли D является B1 и B2?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...