这是可能的,并且在您的代码中它不会造成伤害。但这很危险,因为如果您复制 CDad,则键和指针将被复制。但是,指针将指向的对象以及这些对象中的引用将保持不变。如果原始 CDad 对象超出范围,则指针引用的对象中的引用悬空,不再引用有效对象。
也许您可以反转生命周期:在堆上创建键,并将孩子作为班级中的普通成员。因此,如果您复制爸爸,则复制孩子,但不会复制钥匙。我认为密钥是不可变的,因此您可以在多个孩子之间共享同一个密钥。
这带来了另一点:如果您的密钥相当小(阅读:不是很大)并且不可变(因此,如果您更改一个密钥而不是其他密钥,则不会出现更新异常),请考虑不要在堆上创建它 -所以它们也会被自动复制,并在孩子需要钥匙时传递给他们。您可以让它们成为孩子们的正常指针,但我认为这很丑陋,因为孩子不包含密钥 - 但使用它。所以指针/引用或函数参数很适合,但不是“真实”数据成员。
如果你要使用共享密钥和堆上的密钥,你应该使用智能指针——因为你必须跟踪所有的孩子和爸爸。如果最后一个孩子/爸爸超出范围,您必须再次删除密钥。您boost::shared_ptr
为此使用:
class CCarKeys
{
public:
CCarKeys(const string& Name) : _Name(Name) {}
string _Name;
};
class CChild
{
public:
CChild(boost::shared_ptr<CCarKeys> const& CarKeys)
: _Name("Child"), _CarKeys(CarKeys) {}
string _Name;
boost::shared_ptr<CCarKeys> _CarKeys;
void TestHasKeys() {cout << "I got " << _CarKeys._Name << endl;}
};
class CDad
{
public:
// NOTE: null the kid pointers *if* you use raw pointers, so you can check whether
// a boy or girl is present. Without nulling them explicitly, they have
// indeterminate values. Beware. shared_ptr's however will automatically
// initialized to default "null" values
CDad() :
_Name("Dad"),
_HondaCarKeys(new CCarKeys("Honda keys")),
_ChevyCarKeys(new CCarKeys("Chevy keys")) {}
string _Name;
boost::shared_ptr<CCarKeys> _HondaCarKeys;
boost::shared_ptr<CCarKeys> _ChevyCarKeys;
// also use shared_ptr for the kids. try to avoid raw pointers.
boost::shared_ptr<CChild> _Boy;
boost::shared_otr<CChild> _Girl;
void MakeBoy() {_Boy.reset(new CChild(_HondaCarKeys));}
void MakeGirl() {_Girl.reset(new CChild(_ChevyCarKeys));}
};
// main can be used unchanged
当然,您可以通过使 CDad 类不可复制来避免所有这些复杂性。然后你可以使用你原来的解决方案,只是让孩子们使用 shared_ptr 并使孩子们也不可复制。理想情况下,应该使用非共享指针,例如auto_ptr
,但是 auto_ptr 也有一些陷阱,shared_ptr 都避免了:
class CCarKeys
{
public:
CCarKeys(const string& Name) : _Name(Name) {}
string _Name;
};
class CChild
{
public:
CChild (CCarKeys& CarKeys)
: _Name("Child"), _CarKeys(CarKeys) {}
string _Name;
CCarKeys &_CarKeys;
void TestHasKeys() {cout << "I got " << _CarKeys._Name << endl;}
private:
CChild(CChild const&); // non-copyable
CChild & operator=(CChild const&); // non-assignable
};
class CDad
{
public:
CDad() :
_Name("Dad"),
_HondaCarKeys("Honda keys"),
_ChevyCarKeys("Chevy keys") {}
string _Name;
CCarKeys _HondaCarKeys;
CCarKeys _ChevyCarKeys;
// also use shared_ptr for the kids. try to avoid raw pointers.
boost::shared_ptr<CChild> _Boy;
boost::shared_otr<CChild> _Girl;
void MakeBoy() {_Boy.reset(new CChild(_HondaCarKeys));}
void MakeGirl() {_Girl.reset(new CChild(_ChevyCarKeys));}
private:
CDad(CDad const&); // non-copyable
CDad & operator=(CDad const&); // non-assignable
};
如果我必须实现这样的类层次结构,我会采用该解决方案,或者只是将键作为成员删除,并在需要时将它们传递/创建给孩子。关于您的代码的其他一些说明:
- 最好从成员中删除“_”或将它们放在末尾或使用其他符号。以下划线开头后跟大写字母的名称由 C++ 实现(编译器、C++ 标准库 ...)保留。
- 我个人觉得让成员名称和变量以大写字母开头令人困惑。我只是很少看到它。但这没什么好在意的,这只是个人风格。
- 有一条著名的规则(零一无穷)规定,当你得到两件东西时,你通常应该能够拥有任意多件东西。所以如果你可以生两个孩子——为什么不生很多呢?两个似乎是一个任意的选择。但在你的情况下它可能有一个很好的理由 - 所以在你的情况下它是有意义的,请忽略这一点。