「Effective C++ 改訂第2版」 スコット・メイヤーズ 著

Effective C++ 【改訂第2版】 アスキーアジソンウェスレイシリーズ―Ascii Addison Wesley programming series
前に読んだ時よりだいぶ理解できたのだとは思う。でも、前にどの程度「理解できなかった」のかをすでに忘れていて、理解できたという実感は今回もあまりない。とは言え、いろいろ発見があって得るものはあった。


印象に残ったところを少し。本題とは少しずれたところだけど。


クラスAを継承したクラスBがある。引数の型がAの関数にBのオブジェクトを値渡しで入れると、Aのオブジェクトが作られるので、Aとして振舞う。リファレンスで渡すと、オブジェクトはあくまでもBの型なのでオーバーライドしたメンバ関数はBのものが使われる。
こういう振る舞いがやっとイメージできるようになってきた。


std::numeric_limits::min()
これでintの最小値が取得できる。知らなかった。
俺が今まで見た限りでは、「標準ライブラリ」の説明というと「標準テンプレートライブラリ(STL)」の説明が主だったのだけど、STLではなくて「標準ライブラリ」についてももう少し知りたいなあ。


面白かったのは第6章「継承とオブジェクト指向」だ

だから私は、C++のさまざまな機能が実際にはどういう意味を持っているのか、ある特定の機能を使ったらあなたは実際には何を言ったことになるのかを重点的に説明することにしたい。たとえば、publicな継承の意味は「その一種である」であり、それ以外の意味を持たせようとしたら面倒なことになる。同じように、仮想関数には「インターフェースを継承せよ」という意味があり、一方、非仮想関数には「インターフェースと実装の両方を継承せよ」という意味がある。これらの意味を区別できなかったために、数多くのC++プログラマが人知れず苦しんできたのである。

実装時に便宜的にいろいろ変更していると収拾つかなくなることだけは身に沁みて実感している。

スタックも猫もさまざまな型を扱うという点は共通しているが、あなたが自ら問うべき質問は「型Tは、そのクラスのふるまいに変化をもたらすか?」である。もし、Tの違いによってふるまいが変化しないのであれば、テンプレートを使える。Tの違いによってふるまいが変化するのであれば、仮想関数が必要であり、したがって継承を使うことになる。

当たり前といえば当たり前でほとんど無意識に判断しているような事だ。だけど、無意識のうちに行っていた判断を意識できるようにすることは先に進む上で大事なことだ。無意識の判断のちょっとしたずれが積み重なっていく。

こうしてあなたは多重継承の誘惑に直面することになる。表面的には多重継承のほうが簡単そうに見えるのだ。
(中略)
プログラマは、既存の階層構造を大勢のクライアントが使っていることを知っている。ライブラリの変更が大きければ大きいほど、クライアントの混乱も大きくなる。プログラマは、そのような混乱は最小限に留めようと決心する。選択肢の数々を吟味したプログラマは、次のことに気がつくだろう。もしGrasshopperからCricketへ向かう単一のprivate継承リンクを追加すれば、この階層構造には他の変更は必要なくなる。この考えにプログラマは満足の笑みを浮かべるだろう。ほんの少しの複雑さを加えただけで、機能を大幅に増加できる見込みが付いたのだ。
 そのメンテナンスプログラマが、もしあなただったらどうだろうか。誘惑に負けてはいけない。

絶対誘惑に負ける。一人で開発してるのなら修正できるかもしれないけど、こういうふうに他人が、しかも大勢が絡んでくる状況では絶対負ける。さらに締め切りまであったりしたらもう誘惑に負けざる得ないだろう。
こういう状況をソフトランディングさせるには、プログラミング技術や設計技術とはまた別の技術が必要だ。