クラス型の配列のコンストラクタ宣言について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
RIO

クラス型の配列のコンストラクタ宣言について

#1

投稿記事 by RIO » 10年前

C++でのクラス型配列の初期化において
Shot shot[60];
for(i=0;i<60;i++){
shot=new Shot();
}

みたいにしたいのですが、できないです。
ネットで調べるとポインタでできるそうなのですが
Shot* shotP;
shotP=shot;
ってポインタ代入しようとするとエラーになって困ってます。

コード:

#include"ShotP.h";
#include"key.h";
#include "../include/DxLib.h";
#include "math.h";
#include "value.h";
#include "field.h";

int shotPImg;
#define SHOT_P_MAX 60	//画面上に表示できる弾の最大数


//クラス内
//コンストラクタ
ShotP::ShotP():Object(){
	//Object()で初期化する。
}

//関数
void ShotP::move(){
	//設定したパラメータを基に移動の基本型
	//主に本体からまっすぐ直線に(エナの場合)飛ぶ弾
	//敵弾と基本動作は同じだからObjectクラスでまとめるかも
	this->x=GetGapX(this->x,this->v,this->angle);
	this->y=GetGapY(this->y,this->v,this->angle);
}

void ShotP::graph(){
	//描画処理
	//自機を自機座標を中心に描画
	DrawRotaGraphF(this->x,this->y,1.0f,0.0f,shotPImg,TRUE);
}

void ShotP::setParameter(double x,double y,double v,double angle){
	this->flag=1;
	this->x=x;
	this->y=y;
	this->v=v;
	this->angle=angle;
}

void ShotP::main(){
	move();
	graph();
}
	//弾の情報取得(あたり判定とかで使う)
double ShotP::getX(){
	return x;
}
double ShotP::getY(){
	return y;
}
double ShotP::getV(){
	return v;
}
double ShotP::getAngle(){
	return angle;
}
int ShotP::getFlag(){
	return flag;
}

//クラス内ここまで

ShotP shotP[SHOT_P_MAX];
ShotP *shot;


//クラス外
void shotPinitialize(){
	//初期化するだけ
	//画像呼び出し
	shotPImg=LoadGraph("../dat/img/char/bl_00.png");
}
//弾全体を動かす関数
//Main().cppのWeillループの中で常に動いてる子

void shotPset(double x,double y,double v,double angle){
	for(int i=0;i<SHOT_P_MAX;i++){
		//弾の最大数まで回してフラグ立ってるやつだけ動作させる
		if(shotP[i].getFlag()==1){
			shotP[i].setParameter(x,y,v,angle);
			break;
		}
	}
}	

void shotPmain(){
			DrawFormatString(50,150,GetColor(255, 255, 255),"shot[0]:x=%f",shotP[0].getX());
		DrawFormatString(50,170,GetColor(255, 255, 255),"shot[0]:y=%f",shotP[0].getY());

	for(int i=0;i<SHOT_P_MAX;i++){
		//弾の最大数まで回してフラグ立ってるやつだけ動作させる
		if(shotP[i].getFlag()==1){
			shotP[i].main();
		}
	}
}
プログラムの64,65行目でクラスの宣言だけをして、78行目のfor文であらかじめ作っておいたコンストラクタで初期化するようにしたいです…

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: クラス型の配列のコンストラクタ宣言について

#2

投稿記事 by みけCAT » 10年前

RIO さんが書きました:C++でのクラス型配列の初期化において
Shot shot[60];
for(i=0;i<60;i++){
shot=new Shot();
}

みたいにしたいのですが、できないです。

Shotクラスにポインタを受け取るコンストラクタを定義すればできます。
メモリリークにも配慮しました。

コード:

#include <cstdio>

struct Shot {
	static int count;
	int param;
	Shot() {param=count++;}
	Shot(Shot* s) {param=s->param;delete s;}
};

int Shot::count = 0;

int main(void) {
	int i;

	Shot shot[60];
	for(i=0;i<60;i++){
		shot[i]=new Shot();
	}

	for(i=0;i<60;i++)printf("%d\n",shot[i].param);
	return 0;
}
これは解放するべきではないデータを誤って解放するミスのリスクが高く、あまり褒められるコードではないです。
なぜこのようにしたいのでしょうか?単純に下のようにコピーコンストラクタoperator=を用いて初期化してはいけないのでしょうか?
【訂正】このコードで用いられるのはコピーコンストラクタではなく、operator=です

コード:

#include <cstdio>

struct Shot {
	static int count;
	int param;
	Shot() {param=count++;}
};

int Shot::count = 0;

int main(void) {
	int i;

	Shot shot[60];
	for(i=0;i<60;i++){
		shot[i]=Shot();
	}

	for(i=0;i<60;i++)printf("%d\n",shot[i].param);
	return 0;
}
RIO さんが書きました:ネットで調べるとポインタでできるそうなのですが
Shot* shotP;
shotP=shot;
ってポインタ代入しようとするとエラーになって困ってます。
提示されたコードは適当に補うとコンパイルが通るようです。
「ポインタ代入しようと」したコードを見せていただけますか?

コード:

const int TRUE=0;

int LoadGraph(const char*) {
	return -1;
}
int GetColor(int,int,int) {
	return -1;
}
int DrawFormatString(int,int,int,const char*,double) {
	return -1;
}
double GetGapX(double,double,double) {
	return 0.0;
}
double GetGapY(double,double,double) {
	return 0.0;
}
int DrawRotaGraphF(double,double,float,float,int,int) {
	return -1;
}

struct Object {
};

struct ShotP:public Object {
	double x,y,v,angle;
	int flag;
	ShotP();
	void move();
	void graph();
	void setParameter(double x,double y,double v,double angle);
	void main();
	double getX();
	double getY();
	double getV();
	double getAngle();
	int getFlag();
};

/*
#include"ShotP.h";
#include"key.h";
#include "../include/DxLib.h";
#include "math.h";
#include "value.h";
#include "field.h";
*/

int shotPImg;
#define SHOT_P_MAX 60	//画面上に表示できる弾の最大数


//クラス内
//コンストラクタ
ShotP::ShotP():Object(){
	//Object()で初期化する。
}

//関数
void ShotP::move(){
	//設定したパラメータを基に移動の基本型
	//主に本体からまっすぐ直線に(エナの場合)飛ぶ弾
	//敵弾と基本動作は同じだからObjectクラスでまとめるかも
	this->x=GetGapX(this->x,this->v,this->angle);
	this->y=GetGapY(this->y,this->v,this->angle);
}

void ShotP::graph(){
	//描画処理
	//自機を自機座標を中心に描画
	DrawRotaGraphF(this->x,this->y,1.0f,0.0f,shotPImg,TRUE);
}

void ShotP::setParameter(double x,double y,double v,double angle){
	this->flag=1;
	this->x=x;
	this->y=y;
	this->v=v;
	this->angle=angle;
}

void ShotP::main(){
	move();
	graph();
}
	//弾の情報取得(あたり判定とかで使う)
double ShotP::getX(){
	return x;
}
double ShotP::getY(){
	return y;
}
double ShotP::getV(){
	return v;
}
double ShotP::getAngle(){
	return angle;
}
int ShotP::getFlag(){
	return flag;
}

//クラス内ここまで

ShotP shotP[SHOT_P_MAX];
ShotP *shot;


//クラス外
void shotPinitialize(){
	//初期化するだけ
	//画像呼び出し
	shotPImg=LoadGraph("../dat/img/char/bl_00.png");
}
//弾全体を動かす関数
//Main().cppのWeillループの中で常に動いてる子

void shotPset(double x,double y,double v,double angle){
	for(int i=0;i<SHOT_P_MAX;i++){
		//弾の最大数まで回してフラグ立ってるやつだけ動作させる
		if(shotP[i].getFlag()==1){
			shotP[i].setParameter(x,y,v,angle);
			break;
		}
	}
}	

void shotPmain(){
			DrawFormatString(50,150,GetColor(255, 255, 255),"shot[0]:x=%f",shotP[0].getX());
		DrawFormatString(50,170,GetColor(255, 255, 255),"shot[0]:y=%f",shotP[0].getY());

	for(int i=0;i<SHOT_P_MAX;i++){
		//弾の最大数まで回してフラグ立ってるやつだけ動作させる
		if(shotP[i].getFlag()==1){
			shotP[i].main();
		}
	}
}

int main(void) {
	return 0;
}
最後に編集したユーザー みけCAT on 2015年1月03日(土) 23:07 [ 編集 3 回目 ]
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: クラス型の配列のコンストラクタ宣言について

#3

投稿記事 by みけCAT » 10年前

RIO さんが書きました:プログラムの64,65行目でクラスの宣言だけをして、78行目のfor文であらかじめ作っておいたコンストラクタで初期化するようにしたいです…
一般的にC++において「クラスの宣言」とは

コード:

class hoge {
    // 中身
};
のことだと思いますが、ここでRIOさんが言う「クラスの宣言」とは何のことですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

RIO

Re: クラス型の配列のコンストラクタ宣言について

#4

投稿記事 by RIO » 10年前

みけCAT さんが書きました: 一般的にC++において「クラスの宣言」とは

コード:

class hoge {
    // 中身
};
のことだと思いますが、ここでRIOさんが言う「クラスの宣言」とは何のことですか?
ShotP shotP[SHOT_P_MAX];
クラス型の配列を宣言、
new ShotP();で初期化、って思っていたんですが違うんですか?
みけCAT さんが書きました: これは解放するべきではないデータを誤って解放するミスのリスクが高く、あまり褒められるコードではないです。
なぜこのようにしたいのでしょうか?単純に下のようにコピーコンストラクタを用いて初期化してはいけないのでしょうか?
クラス型にクラス型代入できる方法を知らなかっただけです…。元々構造体配列で作っていたやつをクラスに変えただけなので…。
みけCAT さんが書きました: 「ポインタ代入しようと」したコードを見せていただけますか?
ShotP shotP[SHOT_P_MAX];
ShotP *shot;

ここの部分の次に

shot=shotP;って
書いたんですけど、そこでエラーだったので削除してました…。

RIO

Re: クラス型の配列のコンストラクタ宣言について

#5

投稿記事 by RIO » 10年前

みけCAT さんが書きました: これは解放するべきではないデータを誤って解放するミスのリスクが高く、あまり褒められるコードではないです。
なぜこのようにしたいのでしょうか?単純に下のようにコピーコンストラクタoperator=を用いて初期化してはいけないのでしょうか?
【訂正】このコードで用いられるのはコピーコンストラクタではなく、operator=です
構造体が配列宣言していたのでそのままクラスにしたからです…。
というか、構造体にクラスって代入できるんですね…知らなかったです。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: クラス型の配列のコンストラクタ宣言について

#6

投稿記事 by みけCAT » 10年前

RIO さんが書きました:ShotP shotP[SHOT_P_MAX];
クラス型の配列を宣言、
これは不自然な所はないと思います。「クラス」ではなく「クラス型の配列」の宣言ですね。
RIO さんが書きました:new ShotP();で初期化、って思っていたんですが違うんですか?
間違ってはいないですが、初期化の方法はnew ShotP();だけではありません。
RIO さんが書きました:ShotP shotP[SHOT_P_MAX];
ShotP *shot;

ここの部分の次に

shot=shotP;って
書いたんですけど、そこでエラーだったので削除してました…。
shot=shotP;は普通の代入文(というか式)なので、C++では関数の外には書けません。
ポインタかどうかは関係ありません。
あらかじめshotPを静的に確保してもこの場合は意味が無いと思うので、
ポインタを使って配列の宣言と同時に初期化されることを避けたいのであれば、例えば

コード:

#include <cstdio>

struct Shot {
	Shot() {
		puts("Shot constructed");
	}
	~Shot() {
		puts("Shot destructed");
	}
	void run() const {
		puts("Shot run");
	}
};

Shot *shotP[60];

void initialize(void) {
	for (int i=0;i<60;i++) {
		shotP[i] = new Shot();
	}
}

void run(void) {
	for(int i = 0; i < 60; i++) {
		// Shot shotP[60];と宣言した時と違って、
		// shotP[i].run();と書いてはいけない
		shotP[i]->run();
	}
}

void finalize(void) {
	for(int i=0;i<60;i++) {
		delete shotP[i];
	}
}

int main(void) {
	puts("----- execute initialize -----");
	initialize();
	puts("----- execute run -----");
	run();
	puts("----- execute finalize -----");
	finalize();
	return 0;
}
のようにしてはいかがでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: クラス型の配列のコンストラクタ宣言について

#7

投稿記事 by みけCAT » 10年前

RIO さんが書きました:というか、構造体にクラスって代入できるんですね…知らなかったです。
C++では「構造体」と「クラス」はほとんど同じものです。
あるクラスに別のクラスが「代入」できるかは、
代入されるクラスに代入するクラス(またはそれから変換できるクラス)を引数に取る代入演算子が定義されているかによります。
同じクラス間で代入を行う場合は、代入演算子が暗黙に定義されているので、
明示的に宣言しなくても(その動作がプログラマが意図したものであるかは別として)=演算子を用いた代入ができます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: クラス型の配列のコンストラクタ宣言について

#8

投稿記事 by みけCAT » 10年前

そういえばplacement newというのがあるということを思い出したので、
これを使うのもいいかもしれません。

コード:

#include <cstdio>
#include <new>

struct Shot {
	static int count;
	int param;
	Shot() {param=count++;}
};

int Shot::count = 0;

int main(void) {
	int i;

	Shot shot[60];
	for(i=0;i<60;i++){
		new(&shot[i]) Shot();
	}

	for(i=0;i<60;i++)printf("%d\n",shot[i].param);
	return 0;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

RIO

Re: クラス型の配列のコンストラクタ宣言について

#9

投稿記事 by RIO » 10年前

丁寧に教えてくださってありがとうございます。
知らない事ばかりでしっかり理解するのにはまだ時間かかるけど、頑張ってみます。

RIO

Re: クラス型の配列のコンストラクタ宣言について

#10

投稿記事 by RIO » 10年前

…またチェックボックス入れるの忘れてました…

閉鎖

“C言語何でも質問掲示板” へ戻る