Как мне скопировать экземпляр класса с вложенным классом, содержащим член-указатель, во внешний класс?
Начинающий программист C++ здесь. Допустим, у меня есть класс Outer с вложенным классом Inner. Inner содержит указатель члена, установленный во время построения, к Outer. Outer содержит функцию AddNewInner(), которая создает новый Inner, указывающий на себя, и добавляет его в вектор.
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() для добавления Inners к вектору. Однако, я столкнулся с проблемой, когда я пытаюсь создать копию экземпляра 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 в копии, чтобы указать на копию, а не на оригинал. Каков наилучший способ сделать это, или, возможно, есть альтернативный способ сделать то же самое?
2 ответа
Правильно, это ожидаемое поведение. Когда вы создаете копию объекта в 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++:-).
Вам нужно использовать пользовательский конструктор копирования / оператор присваивания для вашего класса. Это позволит вам сделать глубокую копию вашего Outer* mOuterParent
переменная; возможно создание нового.
Когда вы копируете указатель, вы копируете переменную, которая указывает на конкретное адресное пространство в памяти. Копирование указателя дает вам возможность получить доступ к одной и той же "истинной переменной" через две "переменные доступа".
В вашем примере Outer* mOuterParent
переменная конкретного outer
объект всегда будет указывать на одно и то же создание outer
класс указывает на этот указатель независимо от того, сколько копий этого конкретного объекта вы делаете.