[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
どうも、大西( はかせ )です。
前回に続いて2・3年生向けのプログラムのアドバイスをいくつか追記したいと思います。
前回、定数について書きましたが、少し複数人でのプログラミングの場合も考えてみましょう。
値を定数で振っていた場合、初期化する値を変更するとその定数名を利用している部分を
全てコンパイルし直す必要が出てきます。
ですので Math.PI みたいな円周率とか決まりきった値ではなく変更する可能性があるものは
staticな値を返すだけのメソッドで書いたり、外部から読み込むようにしておけば再コンパイルする
必要性が減ります。
例
① int a を LITERAL という定数で初期化していた。-> LITERAL を書き換えると再コンパイル。
② int a を Method() というstaticな関数で初期化していた。
Method内の実装を変更( 返す値を変えた。) -> 呼び出してる側は関数のエントリーポイント跳ぶ
-> Method内の処理が実行されるだけなので、実装が変わっていようがコンパイルし直す必要はない。
C++でクラスの実装を .cpp 側に書いて定義と実装部を分けるのもこういった理由です。
プロジェクトが巨大になってくるとコンパイルに時間がかかるので、複数人で作業する場合は
自分の作ったクラスを使っている相手がコンパイルをし直す必要が可能な限り少なくしましょう。
皆さん、あなたのクラスは独りよがりなクラスになってませんか?
他の人も使うクラスは利用側が書き換える必要性を可能な限り減らしてあげたり、
ちゃんと利用する側のことも考えてコーディングするよう気をつけましょう。
続いては、突然ですが皆さんプログラムのコードちゃんと後々のこと考えて書いてます?
例えば、符号を入れ替える処理を皆さんはどう書きます?
a = -a ; // aという名前の変数があるものとします。
みたいに書く人が多いのではないでしょうか?
以下のように書くとどうでしょう?
a *= -1 ;
3年生の皆さんは白石先生のアーキテクチャの授業でアセンブラ言語をやっているので
乗算って加減算より時間かかるけど、これって本当に効率いい処理なのって思うかもしれません。
しかし、こう考えるとどうでしょう。
後で、こういったコードを書いてる部分を変更する必要が出てきたとします。
以下のような条件になったとしたら上の場合、= の両辺とも書き換える必要が出てきます。
しかし、下のように記述していたら変更するのは左側のみでいいので作業量は半分です。
では、条件を見ていきましょう。
①変数名を変更することになった。
( まぁ、あまりないとは思いますが… 最初からわかりやすい名前を付けりゃいい話です。)
この程度ならVisualStudioとかの置換機能で何とかなるかもしれませんが、
全体に対して行うとその変数名を含んでいる部分まで置き換えてしまうので不具合が出るかもしれませんね。
さっきみたいに変数名が'a'みたいに1文字だけってことはない思いますが、もしこれで置き換えるとすると
'a'が入っている angle みたいな変数名などがまとめて変わってヒドイことにならないよう、
いちいちチェックして置き換えていかなければいかないのでプロジェクトが巨大になってくると
この方法は使えないと思います。すべて置換は怖すぎて僕にはちょっと…
②配列やSTLのコンテナ、ダブルポインタなどになった。
この場合、a[i] とか **a とかに書き換えるので、特に元の型がポインタなどだった時は
その変数にアドレスとしてアクセスしているか、指している先の値にアクセスしているかの
パターンが複数あるので、さらに置換という方法はムリになると思います。
// 例 元は int* だった a を a[2] で置き換える
{
int b = *a ; // これは置き換えてもOK
int* c = a ; // 置き換えられるとマズイ!!
}
その変数が何度も繰り返し使われているとその分だけ書き換える作業が必要になり大変です。
そういう時は参照やポインタを使うといいでしょう。( C++の場合 )
関数の引数で const参照を使うことはあって人はいても、
参照を普通に使うって人はあまりいないんじゃないでしょうか?
こういった時に役立つ参照の使い方を教えます。
以下のような処理があったとします。
#include<iostream>
using namespace std ;
{
A a[10]; // Aクラスはint型を代入・返す、Set・GetValue メソッドを持つとします。
for( int i = 0 ; i < 10 ; ++i )
{
int value = a[i].GetValue() - 3 ;
a[i].SetValue( ++value + rand() );
cout << a[i].GetValue() << endl ;
// 以下にも a[i]を多用する処理が続くとします。
}
}
これをこう書き換えます。
{
A a[10]; // Aクラスはint型を代入・返す、Set・GetValue メソッドを持つとします。
for( int i = 0 ; i < 10 ; ++i )
{
A& alias = a[i]; // 別名って意味。ポインタで受けてもいいよ。
int value = alias.GetValue() - 3 ;
alias.SetValue( ++value + rand() );
cout << alias.GetValue() << endl ;
}
}
なんか無駄な変数ができた気がする人もいるかもしれませんが、
これを a をインデックスから参照するような形になりました。
最初のような場合は
{
A a[10]; // Aクラスはint型を代入・返す、Set・GetValue メソッドを持つとします。
int index[10] = { 3 , 5 , 1 , 2 , 6 , 7 , 9 , 8 , 0 , 0 };
for( int i = 0 ; i < 10 ; ++i )
{
// 以下のように書き換えていく
int value = a[ index[i] ].GetValue() - 3 ;
a[ index[i] ].SetValue( ++value + rand() );
}
}
となりますが、あとの方法なら
{
A a[10]; // Aクラスはint型を代入・返す、Set・GetValue メソッドを持つとします。
int index[10] = { 3 , 5 , 1 , 2 , 6 , 7 , 9 , 8 , 0 , 0 };
for( int i = 0 ; i < 10 ; ++i )
{
// ここを書き換えるだけで済む!!
A& alias = a[ index[i] ]; // 別名って意味。ポインタで受けてもいいよ。
int value = alias.GetValue() - 3 ;
alias.SetValue( ++value + rand() );
}
}
とできます。
インデックスから参照する以外になっても、alias( 別名 )に値を入れている部分を書き換えるだけで済みますね。
時間は有限です。どうあがいても1日24時間なんです。
ゲーム制作でも期限というものはあります。
プログラムを書く際は後々、楽ができるようにこういった点も考えてみてください。
節約できた時間が自由時間に使えたり、ゲームのクオリティアップに費やしたりできるはずです。
僕もまだまだ精進が足りませんので、もっと学んでいこうと思います。
今回はこんな感じでしたが、皆さんのコードのレベルが向上することを祈ってます。
Fin
COMMENT
無題
static インポートのネタもありがとうございます。
無題
今後はもっと読みやすさを重視しようと思います。
無題
全然見やすいのでこの調子でいいと私は思います。
雑記とかUSJとかでこういう有用な記事が埋もれていって残念です。
できればカテゴリをお役立ちorC++入門or大西先輩講座にしてくれると嬉しいです。
無題
周りからは見にくいという感想が多かったので…
後から自分でも詰め込みすぎな感じな気がしてしまったので
複数に分けるようにしたいと思います。
また、ご要望があった通りカテゴリをお役立ちに変更しました。
気が付いたら、周りがたくさん記事書いてて僕もびっくりです。