C ++でオブジェクトモデルを実装するためのライブラリ/アプローチ

StackOverflow https://stackoverflow.com/questions/802706

  •  03-07-2019
  •  | 
  •  

質問

これが以前に尋ねられた場合、おologiesび申し上げますが、用語や質問の仕方がよくわかりません。

C ++でオブジェクトモデルを実装するためのライブラリまたはベストプラクティスがあるかどうか疑問に思っています。これらのクラスのインスタンスが相互に関係を持ち、さまざまなメソッドを介して相互にアクセスできるクラスのセットがある場合、これらのインスタンスとそれらの相互関係を管理するために、基礎となる適切なデータ構造のセットを選択します。これはJavaではメモリの割り当てとガベージコレクションを処理するので簡単ですが、C ++では自分でやらなければなりません。

HTMLのドキュメントオブジェクトモデル(DOM)はその一例です。別の(意図された)例として、これらのクラスがあるとします:

  • Entity
  • PersonCoupleのサブクラス)
  • PropertyHouseのサブクラス)
  • Pet
  • Carhomeのサブクラス)
  • petscarsのサブクラス)
  • childrenspouseのサブクラス)

およびこれらの関係:

  • marriage
    • クラスparents
    • の1 membersを持っています
    • 0以上のクラスownerのクラスstd::map
    • 0以上のクラスstd::vectorのクラス<=>
    • 0以上のクラス<=>のクラス<=>
  • <=>
    • クラスの0または1 <=>があります<=>
    • クラスの0または1 <=>があります<=>
    • クラス<=>の0または1 <=>を持っています(このモデルでは、親は生きていなければ存在しません!)
  • <=>
    • クラス<=>
    • の2 <=>を持っています
  • <=>
    • クラス<=>
    • の1 <=>を持っています

これらのオブジェクトとそれらの関係を考え出したので、それらを処理するためのデータ構造とメソッドとフィールドの作成を開始したいのですが、ここで私は迷子になります。すべてのもの。次のような問題に遭遇する可能性があります:オブジェクトを<=>または<=>に入れたいかもしれませんが、それを行うと、それらのオブジェクトへのポインターを保存できません。またはベクトルが拡大または縮小します。

COMを頻繁に使用していたときに使用した1つのアプローチは、すべてを含む非表示のコレクションを作成することです。コレクション内の各オブジェクトには一意のID(番号または名前)があり、それによってコレクションから検索でき、各オブジェクトにはコレクションへのポインタがありました。そうすれば、別のオブジェクトへのポインターを文字通り保持する代わりに、別のオブジェクトをポイントしたいオブジェクトがある場合、IDを保存し、非表示のコレクションを介して検索できます。参照カウントを使用して、ライフタイムの問題を自動的に処理できます(切り離されたサイクルの場合を除き、時にはそれは問題ではありません)。

他のアプローチはありますか?または、C ++でこの種のものを簡単にするライブラリはありますか?

編集:次に、オブジェクト間の関係が多くの場合に変更される可能性が高いなど、他の問題があります。また、オブジェクトへの参照をどのように保存するか、互いにオブジェクトにアクセスするためのメソッドを提供する必要があります。たとえば、<=> Xへのハンドルがあり、<!> quot; George <!> quot;という名前のXの子を見つけるという概念を表現したい場合、<!> quotという名前を格納する必要があります。 ; George <!> quot;子番号ではなく:子はベクトルに格納され、X.getChildCount()およびX.getChild(0)を呼び出すことができますが、<!> quot; George <!> quot;他の子が<!> quot; George <!> quot;の前に挿入される可能性があるため、常に子番号0であるとは限りません。子ベクトルで。または、Xには<!> quot; George <!> quot;という名前の2つまたは3つまたは4つの他の子がある場合があります。または<!> quot; George <!> quot;彼の名前を<!> quot; Anthony <!> quot;に変更できます。または<!> quot; Georgina <!> quot;。これらのすべてのケースでは、おそらく何らかの種類の一意の不変IDを使用する方が適切です。

編集2:(これを修正したら、少し質問を整理します)メソッドとプロパティ名の選択を処理できます。マップを使用するか、リストまたはベクターを使用するかを処理できます。それはかなり簡単です。具体的に対処しようとしている問題は次のとおりです。

  • 再割り当てされたデータ構造の一部である可能性がある場合に、あるオブジェクトに別のオブジェクトへの参照を保存させる方法
  • オブジェクト間に相互関係がある場合のオブジェクトライフタイム管理の処理方法
役に立ちましたか?

解決

std :: vectorなどの内部にオブジェクトモデルからオブジェクトを格納することと、それらへのポインターを使用することに関する問題について書きました。これは、C ++クラスを2つのカテゴリに分けるのが良いことを思い出させます(ここで用語についてはわかりません):

    オブジェクトモデルの一部であるオブジェクトを表す
  1. エンティティクラス。それらは通常多形性であるか、将来的には潜在的になります。それらはヒープ上に作成され、常にポインターまたはスマートポインターによって参照されます。クラス/構造体メンバーとしてスタック上に直接作成したり、std :: vectorsのようなコンテナに直接配置したりすることはありません。コピーコンストラクタもoperator =もありません(Cloneメソッドで新しいコピーを作成できます)。意味がある場合はそれらを比較できますが(それらの状態)、IDがあるため交換できません。 2つのオブジェクトはそれぞれ異なります。

  2. 値クラス:プリミティブなユーザー定義型(文字列、複素数、大きな数、スマートポインター、ハンドルラッパーなど)を実装します。スタック上で直接作成されるか、クラス/構造体メンバーとして作成されます。コピーコンストラクターとoperator =を使用してコピーできます。それらはポリモーフィックではありません(多態性とoperator =はうまく機能しません)。それらのコピーをstlコンテナーに入れることがよくあります。それらへのポインタを独立した場所に保存することはめったにありません。それらは交換可能です。 2つのインスタンスの値が同じ場合、それらを同じものとして扱うことができます。 (ただし、それらを含む変数は異なります。)

上記の規則を破る理由はたくさんあります。しかし、最初からそれらを無視すると、読み取り不能で信頼性の低いプログラム(特にメモリ管理に関して)につながり、メンテナンスが困難になることに気付きました。


質問に戻りましょう。

複雑な関係と<!> quot; George <!> quotという名前のXの子を見つける簡単な方法でデータモデルを保存する場合、メモリ内リレーショナルデータベースを検討してみませんか?

a)より複雑な双方向リレーションシップとb)異なるオブジェクトプロパティに基づくクエリを効率的に実装する場合、おそらくリレーショナルデータベース内で行うことと非常によく似たインデックス付きデータ構造を作成する必要があることに注意してください。実装は(単一のプロジェクトに多数あるので)本当に効果的で堅牢になりますか?

<!> quot;すべてのコレクション<!> quot;にも同じことが言えます。およびオブジェクトID。とにかくオブジェクトのないIDを避けるために、オブジェクト間の関係を追跡する必要があります。ポインターとはどう違いますか?その他は、メモリ全体に夢中になるのではなく、意味のあるエラーを取得します;-)


メモリ管理のいくつかのアイデア:

  • 強い所有権:一部のエンティティは、その所有者のみが存続することを宣言でき、独立して存在するポインタの可能性がない場合、所有者のデストラクタで(またはscoped_ptrで)削除することができます。

  • 誰かがすでにsmart_ptrを提案しています。彼らは素晴らしいですし、stlコンテナーで使用できます。ただし、これらはリファレンスカウターに基づいているため、サイクルを作成しないでください:-(。サイクルを処理できる、広く使用されているc ++自動ポインターは知りません。

  • 他のすべてのオブジェクトを所有するトップレベルのオブジェクトがあるかもしれません。例えば。多くの場合、すべてのピースがドキュメント、アルゴリズム、またはトランザクションに属していると言うことができます。最上位オブジェクトのコンテキストで作成し、最上位オブジェクトが削除されると(ドキュメントをメモリから削除するか、アルゴリズムの実行を終了すると)自動的に削除されます。もちろん、トップレベルのオブジェクト間でピースを共有することはできません。

他のヒント

これには約100万の(控えめな見積もりで)アプローチがあります。 <!> quot; C ++ <!> quot;でソフトウェアを設計する方法答えは、<!> quot;お使いのソフトウェアは何をするのでしょうか?<!> quot; -人や家に対処したいということを単に知るだけでは十分ではありません。

これはOOPのポイントではありませんか?あなたが求めているのは実装の詳細であり、これらのクラスのパブリックインターフェイスの後ろに隠れていること、したがって、心配する必要はありません。インターフェイスを変更せずに変更できるからです。だから、あなたが提案する方法で試してみてください。その後、パフォーマンス、メモリ、またはその他の問題がある場合、残りのコードを壊さずに実装を修正できます。

データをデータベースに保存し、何らかのオブジェクトリレーショナルマッピングを使用することも、もう1つの見方です。

boost :: shared_ptrを使用して、メモリの問題に対処できます。その後、shared_ptrを自由にコピーしたり、関数から返したり、ローカル変数として使用したりできます。

A Personstd::map< string, boost::shared_ptr<Person> >を持つことができるため、X.getChild("George")は単にマップ内で子を検索し、ポインターを返します。 概念を理解できたと思うので、残りは演習として残しておきます;)

ジェイソン、私のお気に入りのソースは C ++ FAQ Book です。問題は、<!> quot;オブジェクト指向プログラミングにC ++をどのように使用できますか?<!> quot;

SOの答えで言えることはこれです:

これらはすべてC ++のクラスになり、リレーションシップなどは慣れているガベージコレクション言語のようになります。<!> quot; georgeという名前のPersonとChildのリレーションシップが必要な場合<!> quot ;、名前でインデックス付けされたPersonsまたはChildsを格納できるデータ構造を選択します。

メモリ管理は、いくつかのルールに従う場合、実際にはストレートCよりも簡単です:必要なすべてのオブジェクトにデストラクタがあることを確認し、デストラクタがオブジェクトが所有するすべてのものをクリーンアップしていることを確認してから、これらを常に配置するようにしてください不要になったときにスコープから外れるコンテキストで動的に構築されたオブジェクト。それらはすべてのケースをカバーするわけではありませんが、おそらくメモリ割り当ての間違いの80%からあなたを救います。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top