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

4 に答える 4

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[]) ;
};

そして、コンストラクターは、and (および、おそらく)と同様に、andCChildを取る必要があります。この時点で、このレベルの細分性はの責任に直面して無意味であることに気付くかもしれません。あなたはすべての人に与え、発信者にいくつかのメソッドで自分自身を送信するように強制することによって認証要求を持っているので、実行する必要はありません近親相姦またはおむつ交換。ICashProviderIChaffeurCWifeCGirlfriendCBoyfriendDadthisDadthisDadCWife

于 2009-01-29T15:18:45.190 に答える
0

参照渡しは、セマンティクスと、参照渡しの場合はポインター自体で何もできないという事実を除いて、ポインター渡しとまったく同じです。

あなたのコードはOKです。

于 2009-01-29T15:23:28.190 に答える
0

それは可能であり、あなたのコードでは害はありません。ただし、CDad をコピーすると、キーとポインターも一緒にコピーされるため、危険です。ただし、ポインターが指すオブジェクトと、それらのオブジェクト内の参照は同じままです。その後、元の CDad オブジェクトが範囲外になると、ポインターによって参照されるオブジェクト内の参照がぶら下がり、有効なオブジェクトを参照しなくなります。

おそらく、ライフタイムを逆にすることができます。ヒープにキーを作成し、クラス内の通常のメンバーとして子供を作成します。つまり、お父さんをコピーすると、子供はコピーされますが、鍵はコピーされません。鍵は不変だと思うので、複数の子供で同じ鍵を共有できます。

これは別のポイントをもたらします:あなたのキーが適度に小さく(読む:巨大ではない)、不変である(したがって、1つのキーを変更しても他のキーを変更しない場合に更新異常がない場合)、ヒープ上に作成しないことも検討してください-そのため、それらも自動的にコピーされ、鍵が必要なときに子供たちに渡されます。それらを子供たちの通常のポインタにすることはできますが、子供にはキーが含まれていませんが、それを使用しているため、それは醜いと思います。したがって、ポインター/参照または関数パラメーターは適切に適合しますが、「実際の」データ メンバーには適合しません。

共有キーとキーオンヒープを使用する場合は、すべての子供と父親を追跡する必要があるため、スマート ポインターを使用する必要があります。最後の子供/お父さんが範囲外になった場合は、キーを再度削除する必要があります。そのために使用します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 ...) によって予約されています。
  • 個人的には、メンバー名と変数が大文字で始まるのはややこしいと思います。ごく稀にしか見たことがありません。しかし、これはあまり気にする必要はありません。個人的なスタイルの問題です。
  • 有名なルール (ゼロワンインフィニティ) があります。あるものを 2 つ取得した場合、通常、任意の数のものを取得できるはずです。では、2 人の子供を持てるのであれば、なぜ多くの子供を持たないのでしょうか? 2 は恣意的な選択のように思えます。しかし、あなたのケースでは正当な理由があるかもしれません - あなたのケースでそれが理にかなっているときはこれを無視してください.
于 2009-01-29T15:41:00.323 に答える
0

あなたの特定のケースでは、車のキーは永久に付与される可能性は低く、むしろ必要に応じて要求され、要求ごとに付与されます。だからそれはもっと

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

メイン アプリ クラスと子のより一般的なケースでは、main() でアプリと子によって共有されるデータ オブジェクトを作成し、すべてのユーザーに参照を渡します。

于 2009-01-29T15:30:03.823 に答える