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

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

新規登録して質問してみよう
ただいま回答率
85.48%
オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

C++

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

Q&A

解決済

2回答

1025閲覧

構造体のメンバにスマートにアクセスしたい

taroyamada_t

総合スコア5

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

C++

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

0グッド

1クリップ

投稿2020/01/25 12:44

前提

  1. ブロック崩しのような簡単なゲームを作成しようと思った
  2. ボールを表現するために移動するオブジェクト(block構造体)を作成しようと思った
  3. 四角いボールでよかったのでボール自体を表すrectangle構造体と、移動方向とそのスピードを表すvector2D構造体があればよいと思った
  4. それらを実装したが、実際に使用する際冗長な記述を強いられるため、自分の実装は間違っていると感じた
  5. 自らの知恵では解決できなかったため、質問をしようと思った

実現したいこと

構造体(vector2D, rectangle, block)とその関係を正しく定義し、冗長な記述をなくしたい

発生している問題・エラーメッセージ

  • 構造体のメンバへアクセスする際、コードが冗長になる
  • メンバへのアクセスを簡潔にすると、メンバへの演算の記述が冗長になってしまう
  • 理想とする使用方法を考えたが、それにも問題点があるのでもっと良い方法があればそれを知りたい

該当のソースコード

型の定義

c++

1struct vector2D { 2 int x; 3 int y; 4 /* vector2Dの演算子オーバロードを定義(+=, -=, *=, /=) */ 5} 6 7struct rectangle { vector2D position; vector2D size; } 8struct color { /* 内容に関係ないため省略 */ } 9 10struct block { 11 rectangle area; /* ブロックの表示領域(当たり判定) */ 12 vector2D speed; /* ブロックの移動速度 */ 13 color c; /* ブロックが表示されるときの色 */ 14}

実装:現在のコード↓

c++

1block ball{ /* 実際の値は省略 */ }; 2 3void ball_update() //ボールの移動と表示 4{ 5 vector2D ball_delta{ /* 実際の値は省略 */ } // 移動量の計算 6 7 /* ボールの座標更新 */ 8 ball.area.position.x += ball_delta.x; // メンバ指定が冗長 (block.xとしたい) 9 ball.area.position.y += ball_delta.y; // vecter2Dとして演算したい 10 11 /* 各データへのアクセス */ 12 ball.area.position.x; 13 ball.area.position.y; 14 ball.area.size.x; 15 ball.area.size.x; 16 ball.speed.x; 17 ball.speed.y; 18 ball.c; 19 20 /* ボール表示処理をする */ 21 return; 22}

実装:理想のコード↓

c++

1block ball{ /* 実際の値は省略 */ }; 2 3void ball_update() //ボールの移動と表示 4{ 5 vector2D ball_delta{ /* 実際の値は省略 */ } // 移動量の計算 6 7 /* ボールの座標更新 */ 8 ball.position += ball_delta; // vector2D同士の演算 9 10 /* 各データへのアクセス */ 11 ball.x; //ボールのx座標 12 ball.y; //ボールのy座標 13 ball.width; 14 ball.height; 15 ball.area.position.x; 16 ball.area.position.y; 17 ball.area.size.x; 18 ball.area.size.x; 19 ball.speed.x; 20 ball.speed.y; 21 ball.c; 22 23 /* ボール表示処理をする */ 24 return; 25}

理想のコードの問題点

  • ball.xball.position.xが同じものを指すことになる
  • ball.widthball.size.xが同じものを指すことになる

試したこと

struct blockのメンバをprivateにしてアクセス関数を書く

c++

1class block { 2private: 3 rectangle area; /* ブロックの表示領域(当たり判定) */ 4 vector2D speed; /* ブロックの移動速度 */ 5 color c; /* ブロックが表示されるときの色 */ 6public: 7 // コンストラクタ省略 8 /* getter */ 9 int x() { return area.position.x; } 10 int y() { return area.position.y; } 11 int width() { return area.size.x; } 12 int height(){ return area.size.y; } 13 vector2D position(){ return area.position; } 14 vector2D size() { return area.size; } 15 /* setter */ 16 void x(int x) { area.position.x = x; } 17 void y(int y) { area.position.y = y; } 18 void width(int w) { area.size.x = w; } 19 void height(int h){ area.size.y = h; } 20 void position(vector2D p){ area.position = p; } 21 void size(vector2D s) { area.size = s; } 22}

問題点

  • block.x()block.position().xが同じものを指している
  • 関数と通じて値を変更するため、加算などの表現が分かりにくくなってしまう
  • vector2D, rectangle, blockを内包する構造体を定義したときに、アクセス関数をまた書く必要がある

補足情報(FW/ツールのバージョンなど)

Visual Studio 2019でやってます

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

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

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

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

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

guest

回答2

0

ベストアンサー

そもそも論としては、外からデータメンバにアクセスしたいというのが悪い考え方です。 要素の内部にアクセスしなければならないというのはカプセル化に失敗していることの表れだからです。

データメンバの値を取りだして処理するのではなく、メンバ関数を呼び出す形でオブジェクトに対して「依頼」するのがオブジェクト指向の基本的な考え方です。 "Tell. Don't ask." という格言がよく知られています。 もちろんいつもそう理想的に出来るわけではありませんけども。

データを階層的に整理するところまでは良く出来ていると思うのですが、そのデータで何をするのかという振舞い (C++ では要するにメンバ関数のこと) を定義せずに非メンバ関数でまとめてやっているので、外から見ると深い階層構造になるのは仕方のないことです。

オブジェクト指向の考え方を捨てて C のような書き方をするのであればデータの階層化をやめた方が綺麗ですし、オブジェクト指向的に設計するのであれば値を取りだすのをやめてクラスの中 (のメンバ関数) で処理すべきです。

投稿2020/01/25 14:10

SaitoAtsushi

総合スコア5444

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

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

taroyamada_t

2020/01/25 15:40

この考え方で解決できそうです。 ありがとうございました。
guest

0

ball.xとball.position.xが同じものを指すことになる

ball.widthとball.size.xが同じものを指すことになる

なんでball.xとball.position.xあるいはball.widthとball.size.xを分けよう、と思うのでしょう? それを分けようと思わなければ万事解決に思えてしまうのですが。

投稿2020/01/25 13:25

thkana

総合スコア7629

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

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

taroyamada_t

2020/01/25 14:15

1. ボールのx座標を表す、というときにball.xという記述だけで足りるのでball.xでボールのx座標にアクセスできればいいなと考えました 2. ボールの座標をvecter2Dのまま扱えればオーバーロードした演算を使用できてx座標とy座標それぞれに演算を行わなくてよいのでball.positionにとしてアクセスできればいいなと考えました 3. 結果的にボールx座標にはball.xとball.position.xの2つの方法でアクセスできることになってしまいます 4. なので分けようと思ったわけではなく、やりたいことから考えた結果問題が発生してしまいました。 質問1:分けなければ、というのはball.xというアクセス方法をせずにball.position.xという方法でアクセスすればよいということですか? 質問2:アクセス方法一つにしたとしても、positionへのアクセスはball.rect.positionとアクセスしなければならず、冗長な記述をなくしたいという問題は解決していません。ball.positionとしてアクセスするにはどのような実装が良いと考えますか?
KoichiSugiyama

2020/01/25 14:27

横からすみません。thkanaさんが言われているのは、「ball.xとball.position.xが同じものを指してはまずいのでしょうか。気にしなければいいのでは?」ということだと思いますよ。
taroyamada_t

2020/01/25 14:33

ball.xとball.position.xが同じ変数を指しているのは混乱のもとだと思います。 仮に気にしないとしてもすべての問題は解決しません。
thkana

2020/01/25 14:58

ball.xとball.position.xとはそもそも同じものではないのですか、ということです。 同じものを見え方?で分けようとするから混乱するのでは、と思えるのですが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問