c ++: член со ссылкой на родителя - PullRequest
2 голосов
/ 01 ноября 2010

Я ищу хороший шаблон для реализации следующего:

class Outer;


class Inner
{
     Outer * m_outer;

   public:
     InitOuter(Outer * o) { m_outer = o; }
}

class Outer
{
    Inner  m_inner;

  public:
    Outer()
    {
      m_inner.InitOuter(outer);
    }
}
  • Внутренний всегда должен быть создан со ссылкой на внешний
  • m_outer никогда не будет NULL
  • m_outer не изменится в течение жизни Inner

К сожалению, как я понимаю, m_outer не может быть ни ссылкой, ни неизменным указателем, так как следующая инициализациянедопустимо:

Inner::Inner(Outer & o) : m_outer(o) {}
Outer::Outer() : m_inner(*this) {}

, поскольку при инициализации m_inner, Outer не полностью сконструирован и, следовательно, this является недействительным (и может также измениться при дальнейшей инициализации).

Единственная альтернатива, которую я нашел, состояла в том, чтобы сделать конструктор Inner закрытым, а Outer другом Inner.Это немного лучше, но отношения «друг» кажутся сколь угодно сильными (поскольку обычно внутренний класс должен инкапсулировать функциональность).

Как вы реализуете это?


Мотивация: По моемупонимание C ++, «Outer» еще не полностью построено, поэтому доступ к this может юридически вызвать неопределенное поведение (кто-нибудь может подтвердить это - или даже лучше, что это не так?).


И нет, мне здесь не нужна инверсия контроля.Действительно, спасибо, но нет.
Я пропустил такие детали, как скрытие копии CTor + присвоение.

Ответы [ 2 ]

8 голосов
/ 01 ноября 2010
Inner::Inner(Outer & o) : m_outer(o) {}
Outer::Outer() : m_inner(*this) {}

Это прекрасно. Просто сделай это так. Также подумайте, может ли Inner быть вложенным классом (для чего-то вроде итератора это вполне может иметь смысл.

Вы ничего не сказали о том, что вы пытаетесь смоделировать. Следует отметить, что Outer также должен иметь собственный конструктор копирования и оператор присваивания копии или отключить его. В противном случае плоская копия может привести к серьезной катастрофе.

3 голосов
/ 01 ноября 2010

Использование указателя this в списке инициализации создает предупреждение компилятора C4355 с Visual Studio 2008. Исходя из документации, делать это не рекомендуется, поскольку вы передаете указатель на неструктурированный объект другому объекту,Если конструктор этого другого объекта обращается к любому из членов или вызывает методы неструктурированного объекта, результаты не определены.

Однако в показанном вами ограниченном сценарии вы не делаете ничего, что могло бы вызвать неопределенное поведение,Вы просто устанавливаете переменную m_outer, чтобы указывать / ссылаться на неструктурированный объект.Пока вы ограничиваете это, вы можете делать это, если предупреждение компилятора не является пробой-показом (наш проект имеет стандарт, согласно которому все предупреждения компилятора должны быть удалены).

Если это все ещеВас беспокоит, вы можете изменить код следующим образом.

class Outer; 

class Inner 
{ 
     const Outer & m_outer; 

   public:
     Inner(const Outer & o) : m_outer(o)
     {
     }
} 

class Outer 
{ 
    Inner * m_inner; 

  public: 
    Outer() 
    { 
        m_inner = new Inner(*this);
    } 
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...