2

オブジェクト インスタンスを別のクラスのメンバー変数として処理するためのベスト プラクティスを知りたいです。さまざまな投稿を読んだ後、一般に、メンバー変数としてオブジェクトへの参照を持つことは避けるべきであるように思われますが、ポインターを使用することが良い解決策であるかどうかはわかりません. もう 1 つの可能性はconst、クラス コンストラクターのパラメーターとして参照を持ち、コピー コンストラクターを使用してメンバー変数を初期化することです。

  • この状況を処理するための経験則は何ですか?
  • share_ptrメンバー変数として使用するのはどうですか?
  • メンバー変数が抽象クラスを参照している場合はどうなりますか? この場合、ポインターまたは参照に代わる他の方法はありますか?

編集:

質問に対する答えは文脈に大きく依存する可能性があるため、クラス メンバが抽象クラスを参照する場合に指定します。例として、戦略パターンを実装する次のコードを考えてみましょう。

 class Client{

        // reference to Abstract strategy
        void execute(){
             strategy.doStuff();
        }
 }

 class AbstractStrategy{

 public:
      virtual void doStuff() = 0;
 }

 class ConcreteStrategy{
      void doStuff(){}
 }

には純粋仮想関数があるためAsbtractStrategy、それを のメンバーとして持つ唯一の方法Clientは、ポインターまたは参照を使用することです。より良い解決策はありますか?

4

2 に答える 2

2

あなたの質問に対する唯一の答えはありません。考慮する必要がある要因は、オブジェクトの有効期間です。オブジェクト A が何らかの形でオブジェクト B を「含む」場合、オブジェクト B はオブジェクト A または「悪いことが起こる」よりも長く存続する必要があります。

スマート ポインター (shared_ptr、unique_ptr) を使用すると、オブジェクト A の処理が完了するまでオブジェクト B を削除できないというルールをオブジェクト A に適用させることができるため、スマート ポインターは良い考えです。

オブジェクト B をオブジェクト A にコピーすると、オブジェクト B の有効期間が保証されますが、2 つの別個のオブジェクト B があることに注意する必要があります。これが受け入れられるかどうかは、あなたが決めることです。

A は B の寿命を制御できないため、ポインターと参照は一般的に問題がありますが、プログラムの全体的な構造によっては問題にならない場合もあります。

概要: オブジェクトの有効期間を理解し、どのツールを利用できるかを理解してください。

于 2015-03-12T15:25:30.897 に答える
2

確かに (生の) ポインターに問題はありません。あなたはただ責任を負わなければなりません。参照するオブジェクトを変更する場合は、ポインターを介してメンバーを実装します。そうしないと、別のレベルの間接化を追加しても意味がありません。メモリ使用量と CPU 時間の両方の点で、通常のメンバー変数として持つ方が効率的です。 .

Personクラスは、ageメンバーを数値へのポインターとしてではなく、数値として持つ必要がありますが、個人のメンバーは、住宅residenceのコレクション内のオブジェクトを参照するためのポインターである可能性があります。また、個人が住居を管理したり、スマート ポインターを使用したりする必要があるとは限りません。住居データ レイヤーは、個人レイヤーから完全に独立している可能性があります。個人と一緒に住居を削除することはほとんど意味がありません。空くだけ。

それはすべて、必要なものに依存します。オブジェクトが何かである必要があるか、何かを持つ必要があるか、単に外部の何かを参照する必要があります。

間接化にはコストがかかることに注意してください。これが、メンバをポインタとして実装する意味がほとんどない理由ageです。人々はあまり長生きしません。年齢を格納するために 1 バイトで済む可能性があります。また、年齢のコレクションとポインタは通常 4 バイトまたは 8 バイトであり、ポインタが参照するバイトに加えて、そのメモリ アドレスのデータを取得するためにメモリと CPU 時間を浪費するため、ユーザーごとに 1 つを参照します。しかし、住居は大きなオブジェクトである可能性があり、人物と密接に結びついているわけではないため、人物の住居をポインターとして実装することは理にかなっています。また、スマート ポインターは人物が削除されると住居を削除しますが、通常のポインターを使用すると、人物の住居の居住者参照からその人物を登録解除することができます。

また、これも考慮してください-オブジェクト間に抽象化がある場合があります。たとえば、各人に住居ポインターを持たせたくない場合や、複数の住居の場合は複数にしたい場合があります。実際、人は住居の存在について何も知らない可能性があります。メンバーなどを保持せずに第 3 のオブジェクトを使用することで、個人と住居の間の関係を確立することもできます。たとえば、オブジェクトと住居のポインターのマップなどです。そのため、マップを照会することで、個人の住居があれば取​​得できます。 、すべての人の居住地ポインターを持つよりも遅くなりますが、人のすべてのインスタンスの居住地ポインターを保存しないことでメモリを節約できます。住居がまったくない可能性があります。

抽象クラスについては、インスタンス化できないため、メンバーオブジェクトとして持つことはできません。また、インターフェイスを定義することが目的であるため、仮想ディスパッチとポリモーフィズムを利用するポインタになる可能性が最も高いでしょう。集約とは別に、継承も使用できることに注意してください。オブジェクトごとに 1 つの戦略があり、すべてのオブジェクトがそれを持っている場合、集約と継承の両方でうまくいきます。複数のオブジェクトと複数のオブジェクトがないオブジェクトがある場合は、前の段落で説明した分離設計を使用できます。また、継承を使用すると、そのオブジェクトの vtable の一部になることにも注意してください。つまりStrategy::doStuff()、その特定のタイプのすべてのオブジェクトは、同じコードが実行されることになります。集約やその他のカップリングを使用すると、インスタンスごとに戦略を設定できます。

于 2015-03-12T15:26:57.577 に答える