11-3 protectedpublic

前節で、全ての変数は原則として private 部に置く、ということを学びました。こうして情報隠蔽の考え方を理解すると、今度は「関数・手続きもなるべく隠蔽してしまいたい」という欲求が出てくることと思います。そして、11-2 の最初の【練習問題】で確認したように、関数・手続きも private 部に置くことができます。では、公開したくない関数・手続きは private 部に置くことが望ましいのでしょうか?

関数・手続きもできるだけ外部に公開しない、という方針に添って考えると、「インベーダー」フォーム上で外部に公開しなくてはいけない関数・手続きは「Move」「Construct」「Destruct」の3つだけです。この3つさえ外部に公開されていれば、インベーダーとしてちゃんと機能するのです。他の関数・手続きは隠してしまう方が安全です。

しかし、「ボスインベーダー」フォームが登場したことで、少し困ったことになります。「ボスインベーダー」フォームの手続き RandomMove は、もともとの「インベーダー」フォームから見れば外部にあるのですが、RandomMoveSetSpeedGetSpeed を必要とするのです。つまり、RandomMove にとっては、継承した他の関数・手続きに自由にアクセスできる方がいいのです。

ですが、SetSpeedGetSpeed は変数 Speed を直接書き換えてしまうため、public 部に置いて公開することはあまりよくありません。そこで、private, public の他に protected というものが用意されています。(これら3つのことをアクセス指定子と呼びます。) 前出の住宅の図で考えるなら、public 部は玄関の土間、protected 部は玄関の上がりと考えることができます。そして、もともとのフォームを継承した新しいフォームの変数・関数・手続き (「RandomMove」など) は、居住者の子 (すでに自立してもとの家に連ねて家を建てた) と考えられます。

配達員やセールスマンは玄関からしか入ってきません (そして靴を脱いで上がりに上がることもありません) し、居住者の中で彼等に応対する者も限られています。一方、隣に家を建てた子であれば、通用口から家に入ってきてある程度自由にその家の中を歩き回ることができます。

以上、3つのアクセス指定子の違いを端的に言えば、自分だけがアクセスできるようにしたものが private 、他人 (外部) にオープンにしたものが public、自分の子にだけ公開したものが protected であるということになります。

【練習問題】

プログラムを次のように変更してください。

type
  TFormInvader = class(TForm)
  private
    { Private 宣言 }
    X: Integer;
    Y: Integer;
    Speed: Integer;
    Alive: Boolean;
  protected
    procedure Draw; virtual;
    procedure Erase; virtual;
    procedure SetSpeed(S: Integer); virtual;
    function GetSpeed: Integer; virtual;
    procedure GoHorizontal; virtual;
    procedure GoDown; virtual;
    procedure HitCheck; virtual;
  public
    { Public 宣言 }
    procedure Move; virtual;
    procedure Construct; virtual;
    procedure Destruct; virtual;

  end;

コラム 継承されても使われない関数・手続きは protected 部ではなく private 部に置く方がいいのでは?

確かに、一見その方がより安全に見えます。しかし、考えてみてください。あなたが最初にインベーダーフォームを作った時点では、ボスインベーダーフォームを作るということは考えていなかったはずです。もしこの時点で殆どの関数・手続きを private 部に置いていたら、ボスインベーダーフォームを作る時点で困ってしまったでしょう。

つまり、もともとのフォームを作っている時点では、そこからどんなフォームが派生する (継承される) のか、完全に予測することはできないのです。もしかしたら、あなたが作ったフォームを別の人が継承して新しいフォームを作るかも知れません。そしてそれは、あなたが思いもつかない斬新なものかも知れません。

だから、公開したくない関数・手続きは原則として protected 部に置くのです。

【基礎課題 11-5】

invader_boss ユニットの手続き RandomMove も、private 部, protected 部, public 部のうち適切なところに移してください。

ここまでのプログラムをダウンロード(D)