• ベストアンサー

循環参照の問題に関して。

現在設計の段階なのですが、あるクラスが循環参照に陥りそうで実装に踏み切れません。 現在の状況で循環参照の問題が発生するのか、またどのような開発が循環参照の問題になるのか、教えていただきたいと思います。 現在の状況は、 mainにControlというクラスが実体で多重度1で持たれている。 ControlにDeviceというクラスが多重度0..nでポインタでもたれている。 DeviceというクラスはControlというクラスの参照を持つ。 このような状況になっています。 問題の関係はControlとDeviceです。 このような状況に詳しい方がいらっしゃいましたら、回等をお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • koko_u
  • ベストアンサー率12% (14/116)
回答No.2

コード上は問題ないので、個人的な印象だけ。 このままの設計だと、Control と Device の結合が強すぎるように思います。Device から見て自分が「格納される」オブジェクト(つまり Control)の情報が欲しいというケースはよくありますが、こういう場合は Device が必要とする操作群を別のクラス ControlInfo に切り出して class Control : public ControlInfo { private: std::list<Device*> devices_; }; class Device { private: ControlInfo& info_; }; とかするかな。 #適当に書いてるだけなので、あんまり参考にしないように。

shirousa01
質問者

補足

回答ありがとうございます。 コメントが遅くなってすみません。 現在、koko_u様の意見を参考にして、結合を弱くするためにインターフェイスとしてのクラスを別に定義して、結合を弱くしました。 親の情報が欲しいというのはやはり設計段階で時折、回避できない用件として出てくることですので、今後意見を参考にし、設計を行うように心がけます。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (2)

  • guccii
  • ベストアンサー率31% (14/44)
回答No.3

誘導可能なコンポジッションというだけだと思います。どうしても気になるのなら、前の回答者様のおっしゃるとおり、Controlの中でDeviceが必要とするもののインターフェースを定義してdelegateするか、あるいは、FactoryMethodを用意して参照の設定を隠蔽しておけば、特に問題になることはないと思われます。この場合には、関係が固定的で、一般化の必要性もあまり感じとれませんから、それほどのこともなさそうに思えますが...。

全文を見る
すると、全ての回答が全文表示されます。
  • clsdi99
  • ベストアンサー率63% (31/49)
回答No.1

このような状態を循環参照というかちょっと微妙なきがしますが・・・ 要はこんな感じなのですよね? class Control { std::list <Device *> m_device; ... }; class Device { Control &m_control; ... }; とくに問題ないと思うのですが・・・ インスタンスの作成に関して危惧されているのでしょうか?

shirousa01
質問者

お礼

回等ありがとうございます。 まさにその状況です。 参照が循環する情況に不安を覚えています。 なるべくこのような状況は避けてきたので、初めて回避できない状況におかれて、実装が進んだ後に、この状況で私の対処できない問題が発生してしまいますと、対応に時間をとられてしまいますから。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • c++でのヘッダーファイルの循環参照

     c++言語においての質問です.  A, Bという二つのクラスを作ったとします.  宣言は.h,実装は.cppで行っています. 【A.h】 class A{ //内容 public: B ConvertB(); }; 【B.h】 class B{ //内容 public: A ConvertA(); };  上のように,クラスAではクラスBを返すメソッド. クラスBではクラスAを返すメソッドを実装したいとします.  しかし,単純に 【A.h】に #include "B.h" 【B.h】に #include "A.h" などとすると当然循環参照になってエラーになりますよね? ...とは言っても, 【A.cpp】や【B.cpp】にインクルードした所で, ヘッダ側でエラーが起きてしまいます.  そこで,私の場合は... 【A.h】の先頭に class B{ConvertAで用いるメソッド}; 【B.h】の先頭に class A{ConvertBで用いるメソッド};  というようにする事でなんとかエラーを避けています.    ...しかし,この方法ではAやBのクラスの定義を修正する場合に, 2つのファイルのヘッダを書き換えなければならなくなります. A, B, C, D...などとクラスが増えていくと, 一つのヘッダーファイルに4つも5つもクラスの定義を書かなければなりませんし, クラスのメソッドの定義を一つ変えようとしただけでも, 複数のヘッダの内容をいじらないといけません.  非常に読みにくいコードになってしまうのです.  そこで,もう少しスマートに実現する方法は無いでしょうか?  JavaやC#を使えば簡単に解決するのですが...ライブラリの関係でC++を使わなければ ならないのです.  もしくは,このような相互変換?のクラスを作る場合はみなさんはどのようにして ヘッダーファイルの循環参照を避けているのでしょうか?  例えば様々な形式の色空間のクラスなどだったら... RGBクラス YCrCbクラス HSVクラス ...など  このようなクラスを作った後で,RGBをYCrCbに変換出来るようにしたり, その逆へも変換出来るようにしたいのです.  それともこのような変換が出来るクラスを作る事は間違っているのでしょうか?    よろしくお願いします.

  • クラスの練習をしています。

    ある方から、「参照(もしくはポインタ)を使って、人オブジェクトがまるで建物オブジェクトAから建物オブジェクトBに移動したようにしなさい」と言うお題を頂きました。 「生き霊」がなんちゃらとも言ってたのですが、 私は、人クラスを例えばmainでインスタンス化して、その実体をコピーさせて建物クラスAと建物クラスBにそれぞれ置き、それらを同期させてみてはと考えたのです。 初心者なので説明が難解してると思いますが、もし意図しているものが汲み取れた方がいらっしゃったら、 クラスの参照(もしくはポインタ)の扱い方(?)を教えてください。

  • 参照型を格納できるコンテナについてなど

    ちょっと長文です。下のほうに質問があります。 STLのvectorコンテナを使用しているのですが、 困った事態が発生しています。 自分は、参照型を要素として、持たしたいのですが、 持たすことができません。 なにやら調べてみたところ、STLのコンテナクラスというのは 基本的に「値ベースのコンテナ」らしく、「参照ベースのコンテナ?」 としてコンテナを使うには、ポインタ型を格納して下さい。との ことでした。 ただし、この方法は2重deleteが発生する危険性を孕んでいるので、 Boostのなんかのポインタークラス?のようなものを使えば、 そのような問題に悩まされることないですよー。とありました。 ここで問題なのは、 ・Boostを扱えるだけの知識がない。 ・そもそもBoostを使えるまで環境設定できる自信がない。 ということです。 そのため、普通のポインタを使って実装しようと思うのですが、 そして上記のような問題が出てくるにつれ自分の中では 次のような疑問点が出てきました。 ●質問(1) ・なんで参照型を格納できるコンテナがないのよ!  本当はあったりするんだけども、自分が知らないだけ? ●質問(2) ・関数間でオブジェクトを渡すときには、パフォーマンスとかも  考慮してもconstキーワードを使いつつの参照渡しがよい。と  Effective C++か何かで読んだのですが、コンテナに格納する  場合にはこれは有効ではないのか?  また、オブジェクトは、基本的には、やたらめったら  コピーするものではなく、一つオブジェクト用のメモリ領域を  作ったらそれを流用(ポインタ・参照を使って参照する)した方が、  作り的にきれいな気がするのですが、なにか方針とかあったりする  のでしょうか? 以上長くなってしまいましたが、よろしくお願いいたします。

  • 誘導可能なコンポジションの循環参照について。

    Javaの設計についての基本的な質問です。 企業を表すCompanyクラスのフィールドに、そこで働く従業員を表すEmployerクラスのSetを保持していたとします。 Employerクラスは自身の所属するCompanyを取得するためのメソッドgetCompany()を持っていたとします。 public class Company{   Set<Employer> employers; } public class Employer{   public Company getCompany(){   } } 実現したいのは「従業員から自身の所属する企業を知る」ということです。 このgetCompany()を実現するためにはEmployerのフィールドに所属するCompanyのインスタンスを保持することになると思います。 また、特にDIなどは考えないとすると、Employerクラスのインスタンス生成時等には所属するCompanyクラスのインスタンスを渡すなどの必要があります。 上記のようにすれば実現自体は可能なことはわかるのですが、循環参照のような形となり適切でないような気がします。 Company has employers. は正しいと思いますが、 Employer has a company. は何か違う気がします。 EmployerのコンストラクタにCompanyを渡して、生成したEmployerをそのCompanyにaddするのも不自然に感じます。 これらを実現するためにはどのような形が適切と言えるのでしょうか。 上記は最も正しい・美しい形といえるのでしょうか。 そもそも何か根本的なところが誤っていますでしょうか。 これはあくまで例ですが、回答いただくには情報が足りないのであればご指摘ください。 結果、 http://okwave.jp/qa/q2652715.html こちらの質問と全く同じになってしまいましたが、Javaでも同様でしょうか。

  • boolean型を参照渡ししたい

    boolean型を引数で参照渡しにするにはどうすればいいのでしょうか。 そんな変な実装はしてはいけない等はわかっています。 参照渡しは可能か、もし可能ならば記述方法を教えて下さい。 よろしくお願いします。 下の例の(1)ようにラッパークラスを使ってみましたが、 (2)の部分では値はfalseのままでした。 public main(){     Entity entity;     Boolean flg = false;     sub(Entity entity, Boolean.valueOf(saveFlg)); …(1)     (2) } public void sub(Entity entity, Boolean flg){     flg = true;     return; }

    • ベストアンサー
    • Java
  • 参照型の変数をポインタ引数を持つ関数に引数を書く方法

    C++の参照を使って以下のソースを試したのですが、 memmoveの引数のところでエラーが出ます。 memmoveの引数はポインタ型で合いません。 実体コピーしたい場合、どのようにすればよいのでしょうか? const AA &aとすれば、a自体が関数内で書き換わる心配がないので、 C++の参照型は、ポインタより安全と理解しているのですが その認識は間違っていないでしょうか? struct aa{ int x; int y; }AA; void test(AA &a) { AA b; memmove(b, a, sizeof(AA)); } void main(){ AA c; test(c); }

  • C++の練習をしています。

    クラスAをmainでインスタンス化してそれを参照(もしくはポインタ)で他のクラスB内で生成したいのですが、具体的にはどうしたいいでしょうか? またこのような参照は「同期」と似ていると思ったのですが、意味が違うのでしょうか。 初心者で妙な質問かと思いますがどうぞよろしくお願いします。

  • COMオブジェクトの参照カウントついて

    COMオブジェクトの参照カウントついて 例えばDirectX9で device->CreateTexture(&texture); // textureの参照カウント+1 このtextureを複数のクラスが所有した場合、コピー時にAddRefしなくてはいけないのでしょうか? CreateTextureをしたクラスが責任を持って終了時にReleaseをしていれば問題ないでしょうか?

  • 配列のポインタ配列のポインタから元の配列を参照する方法について

    C初心者です。下記の様に配列のポインタ配列を作って、そのポインタ配列のポインタを返すコードを書いて、main関数で元の配列の値を参照したいのですが、上手く参照できずに困っています。下記のコードの問題点も含めて、配列のポインタ配列のポインタから、元の配列の値を参照する方法を教えてください。お願い致します。 short int *motion_data(void) { short int data1[5][7] = { {2377,2174,0,0,0,0,0}, {2377,2377,2784,2648,2648,2648,2377}, {2377,2377,2784,2648,2648,2648,2377}, {2377,2377,2377,2377,2377,0,0}, {2377,2377,2377,2377,2377,0,0}, }; short int data2[5][7] = { {2377,2174,0,0,0,0,0}, {2377,2377,2919,2784,2784,2784,2377}, {2377,2377,2919,2784,2784,2784,2377}, {2377,2377,2377,2377,2377,0,0}, {2377,2377,2377,2377,2377,0,0}, }; short int *po_data[2]; po_data[0] = data1[0]; po_data[1] = data2[0]; return *po_data; }

  • templateクラスについて

    先ほど以下のようなプログラムを書いたのですがコンパイルを通すことができません。 //適当なポインタを保持するだけのクラス template <class _type> class hoge { private:   //適当に変数を保持   _type val; public:   //コンストラクタで適当に値をセット   hoge() : val( 0 ){}   //このクラスから唯一ポインタを引っ張ってくる方法   friend _type getVal( const hoge& foo )   {     // そのまま返す     return foo.val;   } }; void func( const hoge<int>& foo ) {   //値を引き出す   getVal( foo ); } void main() {   //実体化   hoge<int> foo;   //値を引き出す   getVal( foo );   //関数の先で値を引き出す   func( foo ); } 上記のようなプログラムを書いたのですが、main関数内でgetValを呼び出す場合はとくに問題ないのですがfunc関数を呼び出してfunc関数内でgetValを呼び出すと error C3861: 'getVal': 識別子が見つかりませんでした error C2365: 'getVal' : 再定義; 以前の定義は '以前は不明な識別子' でした。 コンパイルされたクラスの テンプレート のインスタンス化 'hoge<_type>' の参照を確認してください というエラーが出てしまいます。 func関数の引数を( const hoge<int>& foo )からvoid func( hoge<int> foo )のように参照渡しから実体渡しに変更するとコンパイルが通り、実行もできるのですが、なぜこれでコンパイルが通るのか理由がいまいちよくわかりません。 またやはり、コンストラクタ、デストラクタの問題などから実体渡しより、参照渡しを使いたいのですがどのようにプログラムを書けば今回の問題を解決できますでしょうか。 よろしくおねがいします。 /* VisualStudio2005 AcademicEdition MicroSoft WindowsXP Professional 32bit */