如果一个对象A包含一个成员对象B,并且对象B有一个指向其父对象A的指针,那么我需要为对象B指定一个复制构造函数吗?
假设没有动态分配。
此外,在这里适用3个规则吗?
假设没有动态分配。
此外,在这里适用3个规则吗?
Container c;
Object mo1; // Q1: should this be valid ? (i.e. is an object without parent allowed
Object mo2 = c.o; // Q2: is this acceptable ? Q3: Who is parent of mo2 ?
struct Container;
struct Object{
Container *parent;
Object (Container *p=nullptr) : parent(p) { cout << "construct object"<<endl; }
// copy constructor or compiler generated one depending on Q2+Q3
~Object() {}
...
};
struct Container {
Object o;
Container() : o(this) {}
};
Object (const Object &o) = delete;
重要提示: 如果Object
需要可复制,请注意Container
也可能需要一个复制构造函数。无论您决定为Object
做什么,如果要复制,您可能需要在Container
中处理它。在Container
中绝不能使用Object
的复制构造函数。
重要提示2: Container
本身可能在更复杂的情况下被使用。以vector<Container>
为例。当向向量添加新容器时,可能会执行重新定位操作,如果您没有提供一个能够处理的Container复制构造函数,则可能会使指针无效!
是的,即使子对象不管理任何句柄或指向资源的指针(这将导致没有此类构造函数的副本盲目共享并导致熟悉的问题),您也应考虑实现复制构造函数。
原因是父级的子项的副本不一定被认为是该父级的子项!
如果将子项的副本视为属于同一父项,并且父项有一个子项列表,则谁的责任是将其插入该列表中?必须在某个地方完成。如果未在复制构造函数中完成,则代码中执行复制的每个位置都必须记住执行一些其他操作,例如copy.register_with_parent()
。任何忘记此操作的地方很可能都是错误。
如果子项的副本不被认为属于同一父项,则天真的成员逐一复制仍将具有父指针。一个对象持有指向并非其实际父项的父指针是什么意思?必须清除该指针或将其设置为“所有孤儿子对象的默认父项”或其他内容。这将在复制构造函数中完成。
如果您不知道这些问题的答案,那么定义一个未实现的复制构造函数,以便在您知道行为应该是什么之前不进行复制。因此,再次声明但未定义复制构造函数!哦,但是父对象不能拥有其派生类对象,除非使用指针分配:
class B;
class A
{
B son;
};
class B : public A
{
A* parent;
};
结果:
field 'son' has incomplete type 'B'
B son;
^
然后,如果您使用分配完成它:
class B;
class A
{
public:
A(void);
~A();
private:
B* son;
};
class B : public A
{
public:
B() {} // <-depends what you want to archieve
private:
A* parent;
};
A::A(void) : son(new B) {}
A::~A() {delete son;}
A
,分配自己的A
对象,还是指向this
?// A class not changed
A global;
class B : public A
{
public:
B() {parent = &global;}
...
A
对象,则需要遵循3(或4)条规则。此外,您的类A
也需要遵循此规则,因为我们将复制父对象,因此每个B
对象都有自己的对象:
class B;
class A
{
public:
A(void);
A(const A& other);
A& operator=(const A& other);
~A();
private:
B* son;
};
class B : public A
{
public:
B() : parent(new A) {}
B(const B& other) : parent(new A(*other.parent)) {}
B& operator=(const B& other);
~B() {delete parent;}
private:
A* parent;
};
A::A(void) : son(new B) {}
A::A(const A& other) : son(new B(*other.son)) {}
A& A::operator=(const A& other)
{
delete son;
son = new B(*other.son);
return *this;
}
B& B::operator=(const B& other)
{
delete parent;
parent = new A(*other.parent);
return *this;
}
A::~A() {delete son;}
B
指向相同的对象基类,不需要像全局变量那样特殊处理:class B;
class A
{
public:
A(void);
~A();
private:
B* son;
};
class B : public A
{
public:
B() : parent(this) {} // pointless, but yeah, nothing else is needed.
private:
A* parent;
};
A::A(void) : son(new B) {}
A::~A() {delete son;}
这不是关于什么应该做和什么不应该做的问题。一切都取决于你想要实现什么。