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

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

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

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

Q&A

解決済

4回答

494閲覧

コンストラクタの引数を減らす方法

ai2playgame

総合スコア15

C++

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

0グッド

0クリップ

投稿2018/07/31 08:18

コンストラクタの引数を減らす一般的な手法が知りたいです。

 例えばPlayerクラスを作成したとします。このPlayerクラスは必須のパラメータとしてHP、MP、初期位置、攻撃力、移動速度等沢山持つ必要があります。

 今、私はこういった状況に直面した時、コンストラクタの引数として取り初期化しています。

<例>

cpp

1class Player{ 2 3private: 4 int m_hp; 5 int m_mp; 6 float m_power; 7 float speed; 8 Vec2 m_coord 9 10public: 11 Player(int hp, int mp, float power, float speed, Vec2 coord) 12 :m_hp(hp) 13 ,m_mp(mp) 14 ,m_power(power) 15 ,m_spped(speed) 16 ,m_cooord(coord){} 17 18};

この例くらいならギリギリなんとかなりますが、今後必須のパラメータを増やした時、どう考えても管理が大変になってしまいます。

そこで、こういったコンストラクタのパラメータが沢山増える時の一般的な対策を教えてほしいです。

大雑把な話になりましたが宜しくおねがいします。

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

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

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

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

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

guest

回答4

0

ベストアンサー

こんにちは。

コンストラクタの引数を減らす一般的な手法が知りたいです。

一般的なものはありません。常に状況に応じて対処するしかありません。

ただ、極端にコンストラクタのパラメータが増えること自体がレアと思います。
それらの多量のパラメータの値は、どのようにして決めるのでしょうか?
例えば、GUIを使って設定するのであれば、コンストラクタで渡す必要はないでしょう。
デフォルト・コンストラクタで何らかの固定のデフォルト値にしておいて、後でGUIで設定すればよいと思います。設定後にターゲットのオブジェクトへコピーすれば良いでしょう。
HDDに保存していたものを回復するようなケースでも同じですね。デフォルト・コンストラクタで初期設定後、load()メンバ関数的なもので回復すれば良いです。
逆に、定数テーブルで初期化したい場合はコンストラクタのパラメータを増やすのがベストと思います。

Windows APIはC言語I/Fでしたので、あまりに多量のパラメータが有る時は構造体に設定してから、それを渡してました。しかし、コンストラクタが自分とほぼ同じメンバ変数群を持つ構造体を受け取る方法はあまり意味がありません。その構造体のコンストラクタで同じ問題が発生しますし、なんと言っても二度手間です。

投稿2018/08/01 01:44

Chironian

総合スコア23272

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

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

0

1つの方法として、パラメータを個別に指定するのではなく、構造体としてまとめて渡すというやり方をよくやります。
そうすれば、構造体のメンバーを増やすだけで済みます。
構造体なので、渡すのは参照を渡します。

C++

1struct Parameter { 2 int m_hp; 3 int m_mp; 4 float m_power; 5 float speed; 6 Vec2 m_coord 7}; 8 9class Player{ 10 11private: 12 Parameter m_param; 13 14public: 15 Player(Parameter& p); 16 17};

構造体にコンストラクタや、代入演算子、コピーコンストラクタなどを作成しておけば、代入も楽に行なえます。

投稿2018/07/31 08:35

PineMatsu

総合スコア3579

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

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

pepperleaf

2018/07/31 11:34

同様にクラスにするのもありかも。
yuki23

2018/08/01 10:48

構造体を使ったら、初期化漏れが発生してしまいますので、よくありません。初期化漏れが発生してもいいのであれば、最初からコンストラクタでの初期化を必須でないとしてしまえばいいだけなので、解決になっていないと思います。
PineMatsu

2018/08/03 08:15

構造体にコンストラクタを記述して初期化すれば良いのでは?
yuki23

2018/08/03 10:42

それを元のクラスに書いたほうがいいのではないでしょうか?
guest

0

コンストラクタの引数に渡せるのであれば、その引数を決めるための情報とアルゴリズムが必ずどこかに存在するはずです。
一つの一般的な解決策としては、単にその情報とアルゴリズムを、コンストラクタの外に置くのではなく中に置けばいいです。
例えば、引数をJSONから以下のようにパースしているのであれば、

JsonObject obj = parse(json_string); new Player(obj["hp"], obj["mp"], ...);

それをコンストラクタ自体に入れてしまいます。

new Player(json_string); ... Player(const string &json_string) { JsonObject obj = parse(json_string); hp = obj["hp"]; mp = obj["mp"]; ... }

投稿2018/08/01 11:23

yuki23

総合スコア1448

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

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

0

各々のパラメータをカテゴライズしてクラス・構造体に分ける等でしょうか。
初期化の際に全ての情報が設定される必要があるのか、デザインパターンなどを考慮して適切な設定を適切なタイミングで行うようにすることで、メソッド経由で設定することもあるでしょう。

ゲームのキャラクターといった例を挙げられておりますが、いくつか参考になりそうなページを列挙しておきます。

https://qiita.com/FlatMountain/items/0b446900ccd058ec9d43
http://marupeke296.com/DP_PR_No1_HitPoint.html
https://eng-entrance.com/what-oop

投稿2018/08/01 04:52

t_obara

総合スコア5488

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問