質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

1058閲覧

HPゼロでオブジェクトを破棄する仕様を作りたいです

Spe3_0624

総合スコア4

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/12/22 08:11

前提・実現したいこと

C++でRPGじみた簡単なゲームを作りたいです。
そこでオブジェクト内のprivateメンバ変数(ここではHP)が0になったら、そのオブジェクトを破棄するという仕様を作りたいです。別クラスのオブジェクト内のメンバ関数(attack関数)でHPがゼロ以下になったらその関数内で、参照中のオブジェクトを破棄したいです。

今回はHPがゼロになる可能性のある関数に、オブジェクトを破棄する仕組みを加えるつもりですが、そもそもクラスの中に、メンバ変数が一定の条件を満たしたときに、オブジェクトを破棄する仕組みがあれば教えてほしいです。

該当のソースコード

言語はc++です
#include<iostream>

using namespace std;

class test{
int HP;
public:
test(int hp){cout <<"コンストラクタ"<<endl; HP = hp;}
~test(){cout <<"デストラクタ"<<endl;}
int getHP(){return HP;}
int setHP(int hp){HP = hp;}
};

class systems{
public:
void damage(int d, test &ob){
int hp;
hp = ob.getHP() - d;
ob.setHP(hp);

if(hp <= 0){ cout << d << " ダメージ受けた!!\n"; cout <<"HPがゼロになった\n"; /* ここで参照中のオブジェクトを破棄  */ }else{ cout << d << " ダメージ受けた!!\n"; } }

};

int main(){
test *t, t1(50);
systems s1;

t = &t1; s1.damage(20,*t); cout << t1.getHP() <<endl; s1.damage(30,*t); cout <<"終了\n"; return 0;

}

### 試したこと ob.~test()で直接デストラクタを呼び出してもうまくいきませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2021/12/22 08:24

この手の場合は別のクラスオブジェクトが管理して、間接的にやるんじゃないかな。
fana

2021/12/22 08:27

> オブジェクトを破棄 する意義がわかりせん. (仮にそのmain()関数内で t1が唐突に解体されたとして,一体何がうれしいのですか?) オブジェクトを「破棄」することが何らかの意味を持つようなコード例を示すことはできませんか?
Spe3_0624

2021/12/22 08:34

testクラスに敵の情報の基を設定して、main関数内で敵を生成したいときに、testクラスを使って、仮引数(敵のHPなど)とともに敵を生成するという仕様で行こうと思ってました。そこで敵のHP(testのオブジェクト内のメンバ変数)が0になったら、そのままオブジェクトが残っていると気持ち悪いので、その時点で破棄したいと考えていました。 確かに今考えると、オブジェクトを破棄する場合は別のクラスなり関数なりを使用して破棄するのも手だと思いました。
fana

2021/12/22 08:45

何と言うか,オブジェクトが唐突に「破棄」されるのだとして,その「破棄」結果があなたのプログラムの動作(?)に何かしらの良い影響を与えてくれるような【仕組み】が無いと意味ないですよね. 【あるオブジェクトを「破棄」したならば,あれがこうなってここがああなるから,それによってこういう動作になってうれしい】みたいな. > オブジェクトが残っていると気持ち悪い とかじゃなくて.
Spe3_0624

2021/12/22 08:59

仕様としては、メンバ変数のHPがゼロになったら、デストラクタが起動して、「敵が倒れた」的な文とともに、次のステージに段階を進める操作を加えたいと考えていました。 仮にここでオブジェクトがそのままになっていた場合、main関数内に新たにHPが0になったかどうかを見極める関数を作らなければならず、その関数を使うタイミングなどが、プレイヤーからの操作によって実行手順が変わるプログラムにおいて少し不便だなと感じたので、HPが0になった時点でオブジェクトを処理する機能を加えたいです。 確かに現状のような小規模なプログラムでは別の方法でもなんとかなるかもしれませんが、ここからシステムを拡大していったときに支障が出ないとも言い切れません。
Serbonis

2021/12/22 09:25 編集

>オブジェクトを破棄 これは、1)オブジェクトのインスタンスを破棄する、2)オブジェクトを再利用できるようにする、のどちらを意図されているでしょうか?
Spe3_0624

2021/12/22 09:30

1)です。testクラスを基に敵(インスタンス)を生成し続け、そのインスタンス内のメンバ関数(HP)が0になり次第破棄するという仕様にしたいと考えています。
Serbonis

2021/12/22 09:58

まず、t1はmain関数を抜けるまで領域を占有しています。デストラクタを明示的に呼び出しでも、それは単にデストラクタというメンバ関数を呼び出すだけで、領域の解放とは直接関係がありません(main関数を抜けるときにもう1回呼ばれます)。1)の意図であれば、敵のインスタンスはnewで適宜動的に確保するのがよいかと思います。そしてインスタンスの破棄はインスタンス自身が行うのではなく、インスタンスを管理する別のクラス(ex.エネミーマネージャー)に行わせる方がよいかと思います。
fana

2021/12/23 01:16 編集

> testクラスを基に敵(インスタンス)を生成し続け (繰り返しになる感ですが) 刻々と生成なり破棄されていくインスタンス群をどうやって管理するのか? という話の想定がまず存在していないと,そもそも「破棄」の効能が不明瞭ですよね. ・生成とはどうやって行うのか? ・生成したからには以降でいつかそいつにアクセスしたくなるだろうけど,それはどうやってやるのか? ・破棄したからには以降はそいつにはアクセスしてはいけないのだろうけど,そのことはどうやって担保されるのか? ・etc... (例えば,既についている回答では std::vector<test> によって管理していますよね)
guest

回答2

0

C++

1#include <iostream> 2#include <algorithm> 3#include <vector> 4 5class test { 6 int HP; 7public: 8 test(int hp) { std::cout <<"コンストラクタ\n"; HP = hp;} 9 ~test() { std::cout <<"デストラクタ\n"; } 10 int getHP() const { return HP; } 11 void setHP(int hp) { HP = hp; } 12}; 13 14class damage { 15 int d_; 16public: 17 damage(int d) : d_(d) {} 18 bool operator()(test& ob) const { 19 int hp = ob.getHP() - d_; 20 ob.setHP(hp); 21 if ( hp <= 0 ) { 22 std::cout << d_ << " ダメージ受けた!!\n"; 23 std::cout <<"HPがゼロになった\n"; 24 return true; 25 } else { 26 std::cout << d_ << " ダメージ受けた!!\n"; 27 return false; 28 } 29 } 30}; 31 32int main() { 33 34 std::vector<test> obs; 35 obs.reserve(10); 36 for ( auto hp : { 50, 15, 60, 40 }) { 37 obs.emplace_back(hp); 38 } 39 std::cout << obs.size() << " remains.\n\n"; 40 41 obs.erase(std::remove_if(obs.begin(), obs.end(), damage(20)), obs.end()); 42 std::cout << obs.size() << " remains.\n\n"; 43 44 obs.erase(std::remove_if(obs.begin(), obs.end(), damage(30)), obs.end()); 45 std::cout << obs.size() << " remains.\n\n"; 46}

投稿2021/12/22 23:06

episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

C++

1#include <iostream> 2using namespace std; 3 4class test{ 5 6 int HP; 7 public: 8 test(int hp){ cout <<"コンストラクタ"<<endl; HP = hp; } 9 ~test(){ cout <<"デストラクタ"<<endl; } 10 int getHP(){ return HP; } 11 void setHP(int hp){ HP = hp; } 12}; 13 14class systems{ 15 16 public: 17 void damage(int d, test *ob){ 18 19 int hp; 20 hp = ob->getHP() - d; 21 ob->setHP(hp); 22 23 if (hp <= 0){ 24 25 cout << d << " ダメージ受けた!!\n"; 26 cout <<"HPがゼロになった\n"; 27 28 delete ob; 29 30 } else { 31 cout << d << " ダメージ受けた!!\n"; 32 } 33 } 34}; 35 36int main(){ 37 38 test *t = new test(50); 39 40 systems s1; 41 42 s1.damage(20, t); 43 cout << t->getHP() <<endl; 44 s1.damage(30, t); 45 46 cout <<"終了\n"; 47 return 0; 48}

Serbonis さんご指摘のとおり、new で動的にオブジェクトを宣言しないと delete できません。

それから、↑のように、new する場所と delete する場所が違うのは大変気持ち悪いです。
systems クラスの中に、敵の生成 (new) するメソッドを作るとかした方がよいと思います。

投稿2021/12/22 11:23

ak.n

総合スコア291

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2021/12/23 03:52

オブジェクトの集合を用意すれば「new で動的にオブジェクトを宣言しないと delete できません」 じゃなくなる。(回答した)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問