通过引用授予子级访问父级成员的权限 - 可以吗?

发布于 2024-07-12 02:10:17 字数 1147 浏览 10 评论 0原文

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();
}

C++ newbie question. Please, verify I'm doing it right.

I have a global application class spawning it's little kids and I need to give the kids access to some of the application facilities. So I decided to pass them to children by reference.

I tested the idea as show below. It seems to work fine. I just wanted to make sure I'm not doing something dangerous. Might be there any pitfalls I overlooked?

Dad creates children and gives them his car keys:

#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();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

淡淡離愁欲言轉身 2024-07-19 02:10:18

通过引用传递与通过指针传递完全相同,除了语义之外,以及如果通过引用传递,您无法对指针本身执行任何操作。

你的代码没问题。

Passing by reference is quite the same that passing by pointer except for semantics and the fact that you can do nothing with the pointer itself if passing by reference.

Your code is OK.

煞人兵器 2024-07-19 02:10:18

在您的特定情况下,汽车钥匙不太可能被永久授予,而是根据需要进行请求并根据每个请求授予。 因此,

class Dad
{
   /** may return NULL if no keys granted */
   CarKeys *requestKeys(CChild forChild);
}

在主应用程序类和子级的更一般情况下,如何在 main() 中创建由应用程序和子级共享的数据对象,并将引用传递给每个人。

In your particular case, car keys aren't likely to be granted permanently, but rather requested as needed and granted on per-request basis. So it's more

class Dad
{
   /** may return NULL if no keys granted */
   CarKeys *requestKeys(CChild forChild);
}

In more genral case of main app class and children, how about creating the data object shared by app and children in main(), and passing thereferences to everybody.

与酒说心事 2024-07-19 02:10:18

这是可能的,并且在您的代码中不会造成伤害。 但这很危险,因为如果复制 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++ std lib ...)保留。
  • 我个人觉得成员名称和变量以大写字母开头很令人困惑。 我只见过很少的情况。 但这没什么好关心的,只是个人风格而已。
  • 有一条著名的规则(零一无限)规定当你得到以下两件事时某事,你通常应该能够拥有其中的任意许多东西。 因此,如果您可以生两个孩子,为什么不生很多孩子呢? 两个似乎是一个任意的选择。 但在你的情况下它可能有一个很好的理由 - 所以当在你的情况下它有意义时忽略它。

It's possible and in your code it's not causing harm. But it's dangerous, because if you copy CDad, then the keys and pointers will be copied along. The objects that the pointers will point to, and the reference inside those objects, however, will remain the same. If the original CDad object then goes out of scope, the references in the objects referenced by the pointers are dangling, referencing no valid object anymore.

Maybe you can to reverse lifetimes: Create the keys on the heap, and the kids as normal members within the class. So if you copy dad, the kids are copied, but the keys are not. I think keys are immutable, so you can share the same key among multiple kids.

This brings to another point: If your keys are reasonable small (read: not huge) and immutable (so you don't have update anomalies if you change one key, but not the others), consider creating it not on the heap too - so they are automatically copied along too, and pass them to the kids when they need the key. You can make them normal pointers of the kids, but i think that's ugly, because the kid does not contain a key - but uses it. So a pointer/reference or a function parameter fits well, but not a "real" data member.

If you are going with the shared key and the keys-on-heap, you should use smart pointers - because you have to keep track of all kids and dads. If the last kid/dad goes out of scope, you have to delete the key again. You use boost::shared_ptr for that:

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

Of course, you can avoid all this complexity by just making the CDad class non-copyable. Then you can use your original solution, just with making the kids use a shared_ptr and make the kids non-copyable too. Ideally, one should use a non-shared pointer, such as auto_ptr, but that auto_ptr has some pitfalls too, which shared_ptr all avoids:

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
};

If i had to implement such a class hierarchy, i would go with that solution, or just drop the keys as members, and pass/create them when needed to the children. Some other notes about your code:

  • Better drop the "_" from members or put them at the end or use some other notation. A name that begins with an underscore and is followed by an uppercase letter is reserved by C++ implementations (compiler, C++ std lib ...).
  • I personally find it confusing to have member names and variables start with an Uppercase letter. I've seen it only very rarely. But this isn't much to care about, it's just about personal style.
  • There is a famous rule (Zero-One-Infinity) that states when you got two things of something, you generally should be able to have arbitrary many things of that. So if you can have two children - why not have many of them? Two seems like an arbitrary choice. But it may have a good reason in your case - so ignore this when in your case it makes sense.
要走就滚别墨迹 2024-07-19 02:10:17

对我来说看起来不错(如果他们只需要钥匙的话)。 他们可能需要爸爸提供一些稍后请求的其他服务 - 例如:

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 构造函数需要采用 ICashProviderIChaffeurCWifeCGirlfriend 也是如此(也许还有CBoyfriend)。 此时,我想您可能会意识到,面对 Dad 的职责,这种粒度级别毫无意义,您只需将 this 交给每个人,然后让 Dad 通过强制调用者在某些方法上发送自己的 this 来验证请求,这样您就不会让 Dad 执行乱伦或更改 CWife代码>的尿布。

Looks good to me (if keys is all they need). They might need some other services from Dad which are requested later - like:

Wallet += MyDad.GasMoney(REQUEST_MAX_AND_PROMISE_TO_BE_HOME_BY_10PM) ;

But they don't have a reference to Dad, so they won't be able to do that. So I would have the CChild constructor take a this reference, too.

class ICashProvider {
public:
  virtual money Request(IPerson,CashRequestFlags) ;
};

class IChaffeur {
public:
  virtual void Drive(IPerson[]) ;
};

etc.

And then CChild constructor would need to take ICashProvider and IChaffeur, as would CWife and CGirlfriend (and CBoyfriend, perhaps). At this point, I think you might realize that this level of granularity is pointless in the face of Dad's responsibilities and you just give everyone this and have Dad authenticate requests by forcing callers to send their own this on some methods, so you don't have Dad performing incest or changing the CWife's diaper.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文