C ++新手问题。请确认我做得对。
我有一个全球应用程序类产生它的小孩子,我需要让孩子们访问一些应用程序设施。所以我决定将它们传给孩子参考。
我测试了这个想法如下所示。它似乎工作正常。我只是想确保我没有做一些危险的事情。我可能会忽视任何陷阱吗?
爸爸创造孩子并给他们车钥匙:
#include <iostream>
using namespace std;
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;}
};
class CDad
{
public:
CDad() : _Name("Dad"), _HondaCarKeys("Honda keys"), _ChevyCarKeys("Chevy keys") {}
string _Name;
CCarKeys _HondaCarKeys;
CCarKeys _ChevyCarKeys;
CChild *_Boy;
CChild *_Girl;
void MakeBoy() {_Boy= new CChild(_HondaCarKeys);}
void MakeGirl() {_Girl= new CChild(_ChevyCarKeys);}
};
int main ()
{
CDad Dad;
Dad.MakeBoy();
Dad.MakeGirl();
Dad._Boy->TestHasKeys();
Dad._Girl->TestHasKeys();
}
答案 0 :(得分:0)
对我来说很好(如果他们需要钥匙)。他们可能需要来自爸爸的其他服务,这些服务稍后会被要求 - 例如:
Wallet += MyDad.GasMoney(REQUEST_MAX_AND_PROMISE_TO_BE_HOME_BY_10PM) ;
但他们没有提及爸爸,所以他们无法做到这一点。所以我也希望CChild构造函数也可以使用this
引用。
class ICashProvider {
public:
virtual money Request(IPerson,CashRequestFlags) ;
};
class IChaffeur {
public:
virtual void Drive(IPerson[]) ;
};
等
然后CChild
构造函数需要ICashProvider
和IChaffeur
,CWife
和CGirlfriend
(和CBoyfriend
也许) 。在这一点上,我认为您可能会意识到,面对Dad
的职责,这种级别的粒度是毫无意义的,您只需通过强制呼叫者为每个人this
和Dad
验证请求在某些方法上发送自己的this
,因此您没有Dad
执行乱伦或更改CWife
的尿布。
答案 1 :(得分:0)
通过引用传递与传递指针完全相同,除了语义之外,如果通过引用传递,则无法对指针本身执行任何操作。
您的代码没问题。
答案 2 :(得分:0)
在您的特定情况下,车钥匙不可能永久授予,而是根据需要提出并按照请求授予。所以它更多
class Dad
{
/** may return NULL if no keys granted */
CarKeys *requestKeys(CChild forChild);
}
在主应用类和子代的更通用的情况下,如何创建由main()中的app和children共享的数据对象,并将其传递给每个人。
答案 3 :(得分:0)
这是可能的,并且在你的代码中它不会造成伤害。但它很危险,因为如果你复制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
};
如果我必须实现这样的类层次结构,我会使用该解决方案,或者只是将键作为成员删除,并在需要时传递/创建它们给孩子们。关于您的代码的其他一些注意事项: