![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e8efa67)
こんばんは、C++のプログラミングについて質問させて頂きます。
現在、クラスを作って簡単なゲームプログラムを組んでいるのですが、メンバ関数内でクラスを宣言すると上手くオブジェクトを作成出来ないのです。
例えば、メンバ関数の外、メイン関数内で
Player Player1 = Player(320,240,100,50,32,32,3,true,"Character/Character1_A.png");
PL_Array[1]=&Player1;
FireBall FireBall1 = FireBall(PL_Array[1]->Ref_x(),PL_Array[1]->Ref_y(),PL_Array[1]->Ref_angle());
ACT_Array[1] = &FireBall1;
とすると上手く動くのですが。
このPlayerクラスPlayer1のコンストラクター内で
FireBall FireBall1 = FireBall(Ref_x(),Ref_y(),Ref_angle());
ACT_Array[1] = &FireBall1;
とすると、FireBall1オブジェクトが生成されないのです。
この状態を改善するためにはどうすればいいのでしょうか、そもそもクラス内で他のクラスを作成する、といった動作自体があまり良く無いことなのでしょうか・・・
お時間がありましたら、お答え頂けると助かります、宜しくお願いします。
No.2ベストアンサー
- 回答日時:
生成はされています。
ただし
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が密接にかかわるクラスだったら
メンバに持たせるのが筋なことが多いですが
たまーにしか関わらないのであれば
特定の関数で受け渡したりしてそこでだけ使った方が良い場合もまた、多いです。
No.3
- 回答日時:
#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が投げられれば、特に対処していない場合一番根本の呼び出し元まで例外が飛んでいくはずです。
No.1
- 回答日時:
オブジェクトの生成自体はできているはずです。
ただ、関数(コンストラクタを含む)を抜けた時点で破壊されているだけです。これをやるなら
FireBall* FireBall1 = new FireBall(Ref_x(),Ref_y(),Ref_angle());
ACT_Array[1] = FireBall1;
と書きましょう。ただし、ちゃんと生成されたか確認することと、デストラクタまたは適切なタイミングで delete することを忘れずに。
# えーと、今の VC++ はちゃんと bad_alloc 投げるんだっけ?>new 失敗時
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(プログラミング・Web制作) pythonのプログラムについての質問です。 1 2023/05/26 10:31
- C言語・C++・C# c言語の問題です 課題1 (二分探索木とセット) 大きさ size の配列 array を考える。す 2 2023/01/10 21:08
- C言語・C++・C# c言語について array[i]-‘0’ これってどーゆー意味ですか? (ちなみに16進数を10進数 5 2022/12/06 18:39
- C言語・C++・C# 3つの倍精度浮動小数点値の平均を求めて、3つの引数全てを平均値に変更するメソッドを作成し、キーボード 1 2022/07/13 16:04
- PHP PHPでCSVを出力するさいに、ループの中で前の行の値を変更したい 1 2022/10/27 14:21
- PHP PHPでCSVを出力するさいに、ループの中で前の行の値を変更したい 3 2022/10/27 17:44
- Visual Basic(VBA) エクセルのマクロについて教えてください。 5 2023/06/02 08:44
- JavaScript オブジェクト配列の各メンバを任意の式で評価して、その評価値が最大のオブジェクトを返す関数はありますか 2 2023/05/20 15:02
- Ruby パイソンプログラミング 2 2022/12/03 18:44
- Visual Basic(VBA) エクセルのマクロについて教えてください。 2 2023/06/04 09:39
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
構造 他のクラスの構造体を別...
-
クラス間でのデータ参照
-
Java リフレクションについて
-
関数内の変数に<summary>コメン...
-
C#のクラスライブラリでメッセ...
-
C#にて別クラスの関数を使いたい
-
C# log4netの使い方
-
Genericsの型パラメータ
-
[C#]XMLシリアライズ:配列が入...
-
c++,ある関数のクラスから別の...
-
違うクラスのデータを読み込む...
-
a href="..." とServlet
-
eclipse3.0 元に戻す最大回数...
-
C++でfriendクラスにしているの...
-
Struts2でのStaticイニシャライザ
-
エクセルVBAで、条件に一致する...
-
「タイプ初期化子が例外をスロ...
-
インスタンス参照でアクセスで...
-
変数名の付け方
-
EXCEL VBAにて動的にCheckBOXを...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
クラス間でのデータ参照
-
関数内の変数に<summary>コメン...
-
c++,ある関数のクラスから別の...
-
範囲外の数値を代入したらエラ...
-
C#にて別クラスの関数を使いたい
-
無名パッケージからのインポート
-
java-別クラスの変数の使い方を...
-
SwingでgetContentPaneのエラー...
-
C++でfriendクラスにしているの...
-
C#でほかのファイルにある自作...
-
Java リフレクションについて
-
Java
-
import と extends について
-
C#のクラスライブラリでメッセ...
-
a href="..." とServlet
-
ひとつのファイルにクラスは1つ?
-
構造 他のクラスの構造体を別...
-
親クラスから子クラスへアクセス。
-
内部クラスのインスタンスを外...
-
visual studioのデザイナ画面で...
おすすめ情報