「関数を作るときは、使う人の視点で使用目的を考えておくといい」と言ってましたけど、いまひとつピンとこないので詳しく教えてもらえますか?
ああ……それはね、できる限り「使いやすいかどうか」を意識するということよ。関数は作る回数よりも、使う回数の方が多いからね。
でも、どうすれば使いやすくなるんでしょう?
関数のプロトタイプ宣言を見ただけで、使い方のイメージがわくようにデザインできるといいわね。
プロトタイプ宣言で使い方のイメージがわくように……ですか!?
そう。C言語では、関数を使う(呼び出す)側から、その関数の中身(実装)が見えないことも多いでしょ?
……そういうことかぁ。
じゃあ。1つ例をあげてみるわね。
今回は、アルファベットの小文字を大文字にするToUpper()
という関数を作るケースについて考えてみましょう。
この場合、例えば次のようなデザインが考えられるのではないでしょうか。
/* codeで、文字コードを受け取る。
* それがアルファベットの小文字だった場合は、大文字に変換して返却する。
* そうでない場合は、codeをそのまま返却する。
*/
int ToUpper(int code);
/* pCodeで、変換対象の文字コードのアドレスを受け取る。
* 文字コードがアルファベットの小文字だった場合は、大文字に変換してpCodeのアドレスに格納する。
* そうでない場合は、何もしない。
*/
void ToUpper(int *pCode);
/* lowerCodeで、文字コードを受け取る。
* それがアルファベットの小文字だった場合は、大文字に変換してpUpperCodeのアドレスに格納する。
* そうでない場合は、lowerCodeをそのままpUpperCodeのアドレスに格納する。
*/
void ToUpper(int lowerCode, char *pUpperCode);
さて、どのデザインを採用すると使いやすくなるでしょうか?
うわぁ。ぜんぜんピンとこないです。
あらら。そうしたら、「どんな風に使いたいか」と考えてみるといいわね。
そっかぁ。やってみます!
だいたいの関数には、使い方のパターンがあるはずよ。
ええと……アルファベットの小文字を大文字にしたいケースって、たぶん文字列ごと変換したいことが多いんじゃないでしょうか。例えば、こんな感じで!
サンプルコード
/* 文字列を大文字に変換する */
void ConvertToUpper(char *pText) {
size_t length = strlen(pText);
for (int i=0; i<length; i++) {
pText[i] = ToUpper(pText[i]);
}
}
ConvertToUpper()
は、文字列に含まれるアルファベットの小文字をすべて大文字に変換する関数です。その実装では、ループ中でToUpper()
を使うことになるでしょう。変換前の文字コードを1つずつ渡して、変換後の文字コードを戻り値で返してもらえれば、自然な流れで処理できます。
バッチリね!この関数の場合は、おそらくこのような使い方が典型的といえるわね。
(やった〜!)……というわけで、
ToUpper()
のデザインは、こちら(1つ目)を採用することになりますね。
/* codeで、文字コードを受け取る。
* それがアルファベットの小文字だった場合は、大文字に変換して返却する。
* そうでない場合は、codeをそのまま返却する。
*/
int ToUpper(int code);
うんうん。これ以外(2つ目や3つ目)のプロトタイプだと、使いづらそうよね。
ここがポイント!
関数を作るときは、利用形態(どんな風に使いたいか)を意識してデザインしましょう。
標準関数は使いやすくできている
ちなみに、ToUpper()
と同じ目的で使われるものとして、toupper()
という標準関数があります。こちらのプロトタイプも、こうなっています。
int toupper(int c);
同じですね。使うときのことを考えてデザインしてくれていると分かります。
へー。標準関数って、ちゃんと使いやすく考えられているんですね!
C++のクラスはどうする?
C++では、関数よりもクラス(class
)の単位で機能を提供したいケースが多いでしょう。その場合、使いやすいかどうかはクラス全体のデザインに左右されます。
そのクラスのインスタンスを生成してから破棄するまでの典型的な使い方を想定して、メンバー関数ごとのプロトタイプを決めるのがいいでしょう。
意図した使い方をしてもらうには?
ところで、「きっとこんな風に使いたいだろう」と想定して関数を作ったとしても、みんなが同じように使ってくれるとは限らないですよね?
そうね。典型的な使い方について考えるときはサンプルコードを書くことになると思うから、せっかくなら、それをヘッダーファイルのコメントやドキュメントなんかに掲載しておくといいんじゃないかしら。
なるほど〜。目に付きやすい場所にあれば、実際に使う人がサンプルコードをもとに実装できますね。
予想外の使われ方によるトラブルも避けやすくなるわね。