- ベストアンサー
メンバ関数内でオブジェクトを作成する方法について
- C++のプログラミングにおいて、メンバ関数内でクラスを作成する方法について質問があります。
- 現在、クラスを作って簡単なゲームプログラムを組んでいますが、メンバ関数内でクラスを宣言してオブジェクトを作成すると上手く動作しません。
- クラス内で他のクラスを作成する動作が問題なのか、それとも別の原因があるのかを教えてください。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
生成はされています。 ただし FireBall FireBall1 = FireBall(Ref_x(),Ref_y(),Ref_angle()); や FireBall FireBall1( Ref_x(),Ref_y(),Ref_angle() ); といった書き方だと、これは「ローカル変数」という扱いになります。 ローカル変数は関数をはじめとする、スコープを抜けるときに寿命が終わりますので コンストラクタが終わってmain関数の方の処理に戻ったら、もう破棄されているというわけです。 main関数内(かつ、特別にスコープを与えない)で作ればmain関数が終わるまでは使える、ということになります。 >クラス内で他のクラスを作成する、といった動作自体があまり良く無いことなのでしょうか・・・ いえいえ、むしろC++ならしょっちゅう行いたいことですよ。 クラスはメンバ関数だけでなくメンバ変数を持てることはご存知ですよね? 例 class BをB.hに作っておくとします。 つぎにclass Aを作るときに /* Bの宣言部がAから見えるようにインクルードします。*/ #include "B.h" class A { B b; //小文字のbの部分は好きな名前 public: A(); ~A(); void f() const; }; これだけでOKです。 これだとAのコンストラクタで作られ デストラクタで破棄されます。 Bのコンストラクタが引数を持つ場合は A::A() : b(引数のリスト) { } などと初期化子リストで明示的に書いてやる必要がありますが もし引数なしなら A::A(){} と、何も書かなくても大丈夫です。 デストラクタではどちらでも何も書かなくて大丈夫です。 使うときは void A::f() const { b.Bのメンバ関数名(); } 等で使えます。(この場合だとBのconstメンバ関数しか使えませんが) ただこの調子で沢山クラスを作ってやってくと #includeが増えまくってしまう という恐れがあります。 これはコンパイル時間の増大や BがAのインスタンスを持ち AがBのインスタンスを持ちたい などといった場合に行き詰るはめになります。 なので、一般的にはこういう方法が良いです。 class B; //Bというクラスが存在するよ、という宣言 class A { /* ポインタや参照で持つ場合は、この時点でBの中身は分からなくていいので、インクルードする必要がありません。*/ B* b; public: A(); ~A(); void f() const; }; そしてソースの方ではB.hをインクルードします。 そして例えばこのように書きます。 A::A() : b(NULL) { b = new B(引数のリスト); //new演算子で動的に確保します } //動的確保をしたら同じ回数だけ、対になるようにdeleteで解放してください。 A::~A(){ delete b; } 使うときはポインタなのでこうですね。 void A::f() const { b->Bのメンバ関数名(); } (この場合だとBの、constでないメンバ関数も使えます) 動的確保、解放の場合は コンストラクタ・デストラクタ以外でも自由なタイミングで確保・解放が出来ます。 ただし、ちゃんと管理しないと メモリリークやアクセス違反が発生する恐れがあるのでご注意ください。 delete NULL; は「何もしない」ということに決まっているので delete したらすぐNULLを代入 delete b; b = NULL; などを徹底しておけば基本的に大丈夫だと思いますが 一般的には「スマートポインタ」という、その辺の管理をほとんど自動的に行ってくれるような手法が使われたりします。 ただ、今回どういう用途なのか分かりませんが メンバとして class B; class A { B* b; public: void f() const; }; と持たせるより 外部で作っておいて class B; class A { public: void f(B* b) const; }; などとしておいて Bを使いたい時だけ void A::f( B* b ) const { b->Bのメンバ関数名(); } などとした方が分かりやすい場合もあります。 それは設計次第です。 AとBが密接にかかわるクラスだったら メンバに持たせるのが筋なことが多いですが たまーにしか関わらないのであれば 特定の関数で受け渡したりしてそこでだけ使った方が良い場合もまた、多いです。
その他の回答 (2)
- LongSecret
- ベストアンサー率68% (22/32)
#1さん >今の VC++ はちゃんと bad_alloc 投げるんだっけ?>new 失敗時 すべてのVC++のバージョンが規格に対してそれぞれどうなってるかは知りませんが C++の言語仕様では明示的に書かない限り コンストラクタでの例外は 「投げられた例外」が呼び出し側に次々に伝搬することになってたかと struct AAAA { AAAA(){ throw 1000; } }; struct BBBB { AAAA a; }; try { BBBB b; } catch ( int i ){ printf( "%d", i ); getchar(); } なのでstd::bad_allocとは限りませんが 仮にstd::bad_allocが投げられれば、特に対処していない場合一番根本の呼び出し元まで例外が飛んでいくはずです。
- hitomura
- ベストアンサー率48% (325/664)
オブジェクトの生成自体はできているはずです。ただ、関数(コンストラクタを含む)を抜けた時点で破壊されているだけです。 これをやるなら FireBall* FireBall1 = new FireBall(Ref_x(),Ref_y(),Ref_angle()); ACT_Array[1] = FireBall1; と書きましょう。ただし、ちゃんと生成されたか確認することと、デストラクタまたは適切なタイミングで delete することを忘れずに。 # えーと、今の VC++ はちゃんと bad_alloc 投げるんだっけ?>new 失敗時