継承とアクセス制御


アクセス指定子・・・privateとpublic

これまでに、クラスのメンバ(変数と関数)へのアクセスを制御する識別子として、privateとpublicの二つを学びました。

クラスを記述するプログラマ Alice は、クラスを利用する人たちが必要になるメンバのみをpublicで宣言します。また、クラスの内部構造のみにかかわるメンバは private に設定し、外部からのアクセスを禁止します。(Aliceの書くクラスのメンバ関数からは、privateメンバもpublicメンバもアクセスできます。)

・クラス内部を隠ぺいすることにより、オブジェクトの独立性が高まります。外部への影響を抑えたまま、クラス内部の変更をすることができるようになります。

・クラスの機能を提供するために本当に必要なメンバのみを公開することにより、オブジェクトの抽象性が上がります。それに伴ってオブジェクトの再利用性も向上します。

クラスのアクセス制御を考えるときには、このようにクラスを書く人、それを使う人とを分けて考えるのが理解しやすいと思います。

例えば、AliceはWindowsプログラミングの上級者で、Windows用のクラスを提供しているとしましょう。小難しい APIの詳細はprivateとして隠ぺいし、初心者のBobにも使いやすい関数のみをpublicとして公開します。Bobは、隠ぺいされたAPIにはアクセスできないのでWindowsのすべての機能を使うことはできませんが、そのかわり小難しい内部を理解しないでも、Windowsアプリケーションを作成することができます。

新しいアクセス指定子 protected

これまでの登場人物は、クラスを書く上級プログラマ Alice と、それを使う初心者 Bob の二人でした。ここで、3人目のプログラマ Charlie が登場します。CharlieもWindowsのことは良く知ったプログラマです。彼は Aliceが作成したクラスを継承を使って機能拡張しようとしています。

Aliceは、Bobにはprivateとして隠ぺいしていたメンバのうちいくつかは、自分のクラスを派生して利用してくれるCharlieには使わせたいと思うものがあります。

このような場合に使用する新しいアクセス指定子がprotected です。protectedメンバ(被保護メンバ変数・関数)は、クラス外部からはprivateと同様にアクセスできませんが、派生クラス(のメンバ関数)からはアクセスすることができます。

Aliceはprotectedメンバを使うことにより、クラス外部への隠ぺいを保ったまま、派生クラスに対してはアクセス権を与えることができます。

publicメンバは、クラス外部からと同様に、派生クラスからもアクセスすることができます。

privateメンバは、クラス外部からと同様に、派生クラスからもアクセスすることはできません。

また、public(だれでもアクセス化) -> protected(派生クラスからアクセス化) -> private (だれもアクセス不可能) という順番で、アクセス制御が厳しくなっていることも理解しておきましょう。


派生クラスの側でのアクセス制御

ここで、派生クラスを書くCharlieの立場になって、派生クラスの書くときの記述を思い出してみましょう。


class derived : public base {
   ...
   ...
};
                        

前回に学んだように、上のコードではbaseという名前のクラスを派生して、derivedという名前のクラスを作成しています。ここでは、baseクラスを派生するときにpublicというアクセス指定子が指定されていますが(赤字の部分)、ここにはpublicのほかにprotectedprivateの識別子を指定することができます。ここに指定するアクセス指定子は、自分の書く派生クラスを通じての基本クラスのメンバへのアクセスを制御しています。

クラスを派生して書くということは、基本クラスにすでに記述してあることを再利用して、追加したい差分だけを新たに記述するということでしたね。基本クラスのメンバは、自動的に派生クラスのメンバになります。派生クラス外部や派生クラスをさらに派生して使う人たちに対しての、基本クラスから受け継いだメンバのアクセス制御をここに記述しているのです。基本クラスで指定されたアクセス制御に加えて、ここで指定したアクセス指定子によって、基本クラスのメンバがアクセスできる範囲が限定されます。

具体例を示す前に、アクセス制御に関する原則を憶えておきましょう。それは「アクセス制御は厳しくする方向にしか変更できない。」ということです。基本クラスを書くAliceが定めたアクセスは、それを派生するCharlieがどのような形で派生しても、その制限を弱めることはできません。

それでは、基本クラスのprivate、protected、publicの各メンバのアクセスが、派生のしかたによってどのように変るかを右のスライドにまとめておきます。


また、派生クラスをつかって差分プログラミングをするという意味で、一番使われる機会が多いpublicを指定して派生した場合のアクセス制御の図を右に示します。public -> protected -> private となるに従って、アクセスできる範囲が狭くなっていくことをよく理解してください。


練習問題 2

以下のソースでは、baseクラスから派生したderivedクラスのメンバに対して、1) main関数(クラス外部から) 2) derivedクラスの派生クラス derived2 のメンバ関数から アクセスしています。この時、derivedクラスを派生するときのアクセス指定子を変更しながら、どこでどのようなエラーが発生するかを確認しなさい。

プロジェクト名はp3k3_2、ソースファイル名は p3k3_2.cppとしなさい。(確認のためのプログラムなので、クラス宣言部と実装部をファイル分割する必要はありません。)

練習問題 3-1

p3k3_3の名前でプロジェクトを作成し、前回作成したStudentクラスの例題ソースをコピーしてプロジェクトに加えなさい。

Studentクラスの以下のメンバ変数のアクセス制御を以下のように設定し、プログラムが動作するように修正しなさい。(その他のメンバ関数は public のままでよい。)

private:
	char name[20];  //氏名
	int kadai1;  //課題1の点数
	int kadai2;  //課題2の点数
protected:
	int ave;   //平均点  
                        

 

練習問題 3-2

練習問題1-5と同様に、StudentExクラスからさらに派生クラス StudentEx2クラスを作成し、新たに課題4の得点を管理できるクラスとしなさい。このとき、各クラスのメンバに対して適切なアクセス指定をすること。