Начинающий программист 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 в копии, чтобы указать на копию, а не на оригинал. Каков наилучший способ сделать это, или, возможно, есть альтернативный способ сделать то же самое?
Правильно, это ожидаемое поведение. Когда вы создаете копию объекта в 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
класс указывает на этот указатель независимо от того, сколько копий этого конкретного объекта вы делаете.