2016-07-25 7 views
0

Новичок C++ программист здесь. Предположим, у меня есть класс Outer с вложенным классом Inner. Внутренний содержит указательный элемент, заданный во время построения, для Outer. Outer содержит функцию AddNewInner(), которая создает новый Внутренний, указывающий на себя и добавляет его к вектору.Как скопировать экземпляр класса с вложенным классом, содержащим элемент указателя во внешний класс?

class Outer { 

public: 

    class Inner { 
    public: 
     Inner(Outer* outerParent) : mOuterParent(outerParent) {} 
     Outer* mOuterParent; 
    } 

    void AddNewInner() { 
     Inner newInner(this); 
     mInnersVec.push_back(newInner); 
    } 

    vector<Inner> mInnersVec; 
} 

Это прекрасно работает при создании нового экземпляра Outer и вызова AddNewInner(), чтобы добавить колбы к вектору. Тем не менее, я столкнулся с проблемой при попытке создать копию экземпляра Outer: вектор внешней копии Inners не указывает на копию (сам), они все равно указывают на исходный Outer.

Outer outerA; 
outerA.AddNewInner(); 
Outer* ptrA = outerA.mInnersVec[0].mOuterParent; // this points to outerA, good! 

Outer outerB = outerA; 
Outer* ptrB = outerB.mInnersVec[0].mOuterParent; // this still points to outerA, bad! 

Мне нужен вектор Inners в копии, чтобы указать на копию, а не на оригинал. Каков наилучший способ сделать это, или, возможно, есть альтернативный способ сделать то же самое?

+0

Aah ....Вам нужно прочитать конструкторы копирования. Google копировать конструкторы, глубокие копии, мелкой копии. Много ссылок. – cplusplusrat

ответ

0

Правильно, это ожидается поведение. Когда вы создаете копию объекта в C++, компилятор использует конструктор копирования . Если вы не написали свой собственный конструктор копий для класса, то он использует созданный компилятором конструктор копирования, который просто запускает (возможно сгенерированный) конструктор копирования для каждого члена по очереди.

Так при копировании Outer, последовательность событий выглядит следующим образом:

  • Компилятор бежит (генерируется) конструктор копирования для Outer
  • Это работает конструктор копирования для std::vector. Этот конструктор назначает хранилище для нового вектора, а затем запускает конструктор копирования для каждого элемента по очереди
  • Таким образом, (сгенерированный) экземпляр копии для Inner запускается для каждого элемента, который просто копирует указатель на элемент (все еще указывая на оригинал Outer).

Для того, чтобы обновить Inner элементов при копировании Outer, необходимо написать конструктор пользовательского копирования для Outer, который обновляет указатели, как вы хотите. Что-то вроде этого:

Outer::Outer(const Outer& other) 
    : mInnersVec(other.mInnersVec) // Do initial vector copy 
{ 
    // Update vector elements 
    for (auto& elem : mInnersVec) { 
     elem.mOuterParent = this; 
    } 
} 

Обратите внимание, что всякий раз, когда вы пишете конструктор пользовательских копий, почти всегда нужно писать оператор присваивания пользовательского тоже. Я бы рекомендовал прочитать на копирование и назначение в вашем любимом учебнике на C++ :-).

0

Для вашего класса необходимо использовать пользовательский copy constructor/assignment operator. Это позволит вам сделать глубокую копию вашей переменной Outer* mOuterParent; возможно, создавая новый.

При копировании указателя вы копируете переменную, которая указывает на конкретное адресное пространство в памяти. Копирование указателя дает вам возможность получить доступ к одной и той же «истинной переменной» через две «переменные доступа».

В вашем примере Outer* mOuterParent переменные конкретного outer объекта будет всегда указуют на ту же конкретизацию в outer класса не указал на этом указатель независимо от того, сколько копий этого конкретного объекта вы делаете.