ストラウストラップのプログラミング入門(22) 第14章「グラフィックスクラスの設計」

ストラウストラップのプログラミング入門』を読む。今日は14章「グラフィックスクラスの設計」です。

14章はとても面白かったです。特に、14.4「オブジェクト指向プログラミングの利点」は、章のハイライトです。余白のアイコンの量からも、この節の濃さが分かりますね!

インターフェイスの継承と、実装の継承という2つの考え方が、わずか1ページ半にまとめられています。(凝縮しすぎだろう常識的に考えて…)

色々わかったこと

12、13章での自分の疑問には、14章で大体答えが示されていました。

  • structとclassの違いについては「話題を変えるほうが生産的」らしい。
  • ウィンドウに図形オブジェクトをattachした後、変更が反映されていたのは、図形オブジェクトを参照渡ししていたからだった。。。

個人的に引っかかっていたLineとLinesについても、次のような概念が、コードに表されていただけだと分かりました。

  • LinesとLineは、Shapeという共通の基底クラスを持つが、相互には関係がない
    • たとえば、LineからLinesを作成するようなことはできない
  • Shapeが持っている「Pointを直接操作する」という振る舞いを、それぞれ引き継いでいる

文法メモ

文法で混乱したので、ちょっと整理します。

※注意: 下表は間違いを含む可能性が高いです。言語の知識がない人は信じないでください。

使いたい言語機能 C++でのやり方 Javaでのやり方
クラスを抽象化する コンストラクタをprotectedで定義する abstract、あるいはinterfaceとしてクラスを定義する
関数を派生クラスでオーバーライド可能にする public、あるいはprotectedな仮想関数にする public、あるいはprotectedなメソッドにする
関数の実装を派生クラスに強制する 仮想関数にして、基底クラスで実装を提供しない abstractメソッドにする
基底クラスのpublic関数のアクセス範囲を、派生クラス側で狭める プライベート基底クラスとして継承する より狭いアクセス範囲のメソッドでオーバーライドする
(しかし、基底クラスのメソッド自体のアクセス範囲を制御することはできない…と思う)

  • C++では、仮想関数にすることで、オーバーライド可能であることを示す
  • Javaでは、finalメソッドにすることで、オーバーライド不可能であることを示す

…のかな、と思いました。が、この対称性の認識にも自信がないです。間違っているかも。

まあ細かいルールを今がんばって覚える必要はないですよね、たぶん。

良い言葉

内部実装を知る必要性の話と、言語の詳細を知りすぎる必要はないという話が、良かったのでメモします。

14.3.1では、オーバーライドの仕組みについて解説されています。インスタンスの仮想ポインタが、個々のクラスと1:1対応する仮想テーブルを介して、仮想関数の実装と関連付けられる、という話です。

興味深く勉強になりますが、また深さ優先な解説ハジマタ、という感じでもあります。そうする理由が述べられています。

ここでvtmlとメモリのレイアウトに言及するのはなぜか。(略)多くの人(特に私たち)は何がどのように実装されるのかに興味津々であり、人々が何かを理解していないときに都市伝説が生まれる。仮想関数は「コストがかかる」といって手を出そうとしない人に会ったことがある。(略)そうした不安を抱かないようにするためだ。

なるほど・・・。一方、14.3.4では、言語仕様の詳細を知ることにこだわりすぎないようにしよう、という話が書かれています。

言語の達人(言語の定義を隅々まで知っている人)になることはお勧めしない。プログラマ(ソフトウェア開発者、エンジニア、ユーザー、あるいは言語を実際に使用する人に対するその他の呼び名)になるほうがずっと楽しいし、一般にそのほうがずっと社会に貢献する。

動く仕組みを理解することはそこそこ重要だけれども、言語仕様を何から何まで知ろうとすることは、前者ほど重要ではない、ということなんですね。

ドリルと練習問題

ドリルもやりました。

(7)の課題設定の意図が分かりません。ある純粋仮想関数を、2つの別々のクラスでオーバライドして、それぞれのクラスに属するstring型とint型のデータメンバを出力せよ、という内容です。

オーバライドされた後の関数は、関数の実装の中で何をしようが(つまり、stringを出力しようが、intを出力しようが)、それぞれ別個に動作するよってことが言いたいんですかねぇ。

練習問題もちょっとやりました。長方形をにするお題です。