関数のオーバーロードと糞コード
大学の演習でとんでもない糞コードが出てきてしまったので投稿です。
1 2 3 4 5 6 7 8 9 10 11 |
#include <math.h> ... int x, y; ... if (fabs((x - 180.0) * (20 - 60) - (230 - 180) * (y - 60)) < 30) { ... } |
このコードは学生が書いたものではなく、教員が書いたコードです。
まず、マジックナンバーをガンガン使うコードを平気で推奨するのもそれなりに問題なんですが、それ以上に問題なのが、fabs
と180.0
です。
整数と整数は+しても-しても*しても実数が必要になることはあり得ないので、実数の絶対値を求めるfabs関数を使う理由がさっぱり分かりません。
また、180.0
のように無理やり実数にして辻褄を合わせるのも意味不明です。
というか<で比較する対象が整数だし、もう分けわかんねえ。
180.0の理由
実は最初は180.0
の部分は普通に180
と整数で書いてありました。
では、なぜ180.0
と実数にしたのか?
結論を言うとコンパイルエラーになるからなのですが、試しにfabs関数に整数を入れて試してみました。
1 2 3 4 5 6 7 |
#include <math.h> int main(void) { fabs(10); return 0; } |
これをC言語としてコンパイルすれば、コンパイルできます。
fabs関数の引数はdouble
ですが、int
はdouble
に暗黙のキャストがされるからです。
今度はこれをC++としてコンパイルしてみます。
すると、コンパイルエラーになります。
C言語のヘッダなのに関数のオーバーロードがされているところ自体「は?」って感じですがそれは置いといて。
C++は引数の型や数が異なれば同じ名前の関数を多重定義(オーバーロード)できるので、どうやらMSVC++2010のfabs関数は
long double fabs(long double)
float fabs(float)
double fabs(double)
の少なくとも3つが定義されているみたいです。
int
はlong double
にもfloat
にもdouble
にも暗黙のキャストが可能です。
となると、一体どの型にキャストしてどの関数を呼べばいいのかはっきりしないので、コンパイルエラーになります。
ではどうすればいいのか、教員がやったみたいに180.0
と小数点を加えるとdouble
の実数になります。
double
* int
は double
になり、型がはっきりするので、コンパイルできます。
めでたしめでたし。
書くべきだったコード
1 2 3 4 5 6 7 8 9 10 11 |
#include <math.h> ... int x, y; ... if (abs((x - 180) * (20 - 60) - (230 - 180) * (y - 60)) < 30) { ... } |
整数ならabs関数を使う、普通!
まとめ
とりあえず、大学側は
- C言語とC++をごちゃ混ぜにしない
- 学生にC言語のソースコードをC++としてコンパイルさせる習慣をやめさせる
- 整数の絶対値求めたいならfabs関数じゃなくてabs関数を使う
ということをすぐにやってもらったほうがいいですね。