C++によるプログラミング入門14
パブリックとプライベート 

こんにちは。「入門」をはじめてずいぶんたちました。
まじめに読んでくれた奇特な方はもういろいろわかってきたかと思うのですが、どうでしょうか。もし、そうならそれでいいですし、もし、まだ、わからないというのでも、また、よいと思います。実際、そろそろ、わからないことが続出するころだと思っています。と、言って無責任なわけではないのです。(まあ、責任というのも変ですが。)
私は勝手にプログラムの勉強の段階を次のように考えています。(これが、自分の歩いてきた、もしくは歩いているコースなのです。)

  入門(初心者・若芽) とりあえずプログラムを書くことを見よう見まねで覚える
  初級(初級者・若葉) その言語の文法上の基礎知識を学ぶ
  中級(中級者   ) データ構造やアルゴリズムの具体的な表現方法を学ぶ
  上級(ウイザード ) なんでもこい!!!

この講座は繰り返すまでもなく入門です。多くの人は初級からはじめるのですが、これはよほど強い意志か才能がない限りすぐ退屈してしまいます。私自身がそうでした。例えば、初級の本には次のようなことが書いてあります。

通常、整数はint型で表される。ただし、int型で表すことのできる整数の範囲は環境によって異なる。16ビットが自然な環境では-32768から+32767まで、また、32ビットが自然な環境では-2147483648から+2147483647までとなるのである。大きい整数を必要とする場合には通常longを使う。ただし、long型は、、、どうたら、こうたら、、、

こういう事にはじめから興味を持てる初心者はたいしたものですが、普通、こういうことに興味があるのはもう初心者のレベルから抜けつつあるのだと思います。
初心者のうちはできるだけ簡単な手順を覚えて、プログラミングを楽しむのが一番だと私は思います。
C言語のバイブル「プログラミング言語C」では、著者カーニハン、リッチーの両大先生も「新しいプログラミング言語を学ぶ唯一の道は、それでプログラムを書いてみることである。」とおっしゃって、はじめの1章を簡単なプログラミングの説明(つまりシステマティックでない説明)にあてています。
私の場合、はじめは、とにかく楽しくプログラムをつくっていたのです。が、そのうちよくわからないことにちょくちょく遭遇するようになりました。それで「まじめにプログラミングをするなら、基礎知識をちゃんと勉強しなければだめだ」などと殊勝なことを考えるようになって、「初級用」の本(つまり上のような記述で埋まっている本)を読み出したのです。すると、実にいいことが書いてあるじゃないですか、と、ようやく納得がいったのでした。
なぜこんなことを言うかというと、もし、私の講座について「言っていることだけに限定すればわかる。でも、何か自分でやろうとするには書いてないことが多い。」という不満を持つならば、それは、そろそろ次のステップへの道が開いてきたのですよ、と言いたかったのです。そいういう人は本屋さんに走って行って自分が気に入りそうな詳しい本を買ってくることを強くおすすめします。
ただ、私の入門講座はまだあと半分くらいはあるので、もう少しつきあってもらえればと思います。これから、継承や仮想関数というC++の山場に向かっていくことになるからです。
一方、まじめな本なんてずっと読みたくないな、という人もいるでしょう。それはそれで良いと思います。プログラミングをはじめた頃の私はそう思っていましたから。ただ、いずれは自らバージョンアップしていくのだと思います。(これは予言です。)


さて、、、。クラスになぜprivate(プライベート)とpublic(パブリック)があるのか、話すときがきたようじゃの、と、村の古老は言った。その目に浮かべた複雑な表情の意味を理解するには、その青年は若すぎるのだった、、、。(なんちゃって。)まあ、お話が多くてもいいですよね。というわけで少しクラスの能書きをたれさせていただきます。
前にも言いましたが、クラスというのはプログラムの部品です。このような部品が重宝されるのは、現在では、基本的に大きなプログラムがつくられるからです。短いプログラムなら部品なんていりません。いっきに書き上げてしまえばいいのです。しかし、そういうプログラムを書いてももう誰もほめてくれない時代なのです。
逆に部品さえあれば大きなプログラムを「楽に」(まあ、そうは言っても大変ですが。^^;)書くことができます。実際、有用な「クラス」は売りに出されていたりして、それを初心者が買ってきて使えば、たちまち初心者製の「大規模プログラム」になるのです。
もちろん、他人のクラスなんぞ,わしは使わんぞい。自分のコードは全部自分で書くわい。という人もいるでしょうが、その場合でも、プログラムの部品化が有用であることは同じでしょう。

実際、「部品化」ということは現代社会では基本的であると思います。例えば、テレビも我々の世界の重要な部品です。(テレビ全体を生活の部品と考えました。テレビを見ない人は別の電気製品を思い浮かべてください。)テレビ(や別の電気製品)で特徴的なことは、

  1.作っている人以外は(普通)中身を知らないし、知る必要もない。
 2.使い方は簡単。つまみやボタンをちょっといじればよい。

でしょう。これは、使いやすい「部品」の一般的な条件ではないでしょうか。実際、内部ではとても複雑なことが行われているはずですが、誰でもテレビのスイッチをいれるとすぐに番組を見ることができます。私はよく知らないのですが、テレビの中身はメーカーによって違うかもしれません。それでもスイッチやチャンネルがついているテレビなら、中身の心配をせずに、安心して使えるのです。
ところで、普通のテレビには、たぶん

  勝手にふたを開けないでください。
  勝手に改造しないでください。

というただし書きがついているはずです。どうしてでしょうか、、、。というまでもないですよね。勝手にテレビを改造して火が出てもメーカーでは責任はとれないということです。
さて、クラスの話にもどります。クラスも日常生活のテレビような存在です。クラスの作者は「このクラスはこのように使ってください。ただし、中身はいじらないようにしてください。」とただし書きをつけるのが普通です。
どこに?それが、クラスのプライベートとパブリック宣言なのです。プライベート(private:と書いてあるか、または、何も書いてない場合)宣言のものは、クラスから作られるオブジェクトの中身に相当します。「触ってはいけない」とわざわざ言っているのです。もちろん、クラスは少しくらい改造しても、火を吹いたりはしないのですが、別の場所でエラーを引き起こしたりするのです。もう一方のパブリック(public:と書いてある場合)宣言のものはテレビで言えば、スイッチやチャンネルに相当します。ここはどう触ってもいいのです。
プライベートとパブリックのある理由、納得いきましたか?実際、実感としてわかるのは、もう少し経験をつんでからだと思います。ただ、そういうもんだと思っておいてください。
もちろん、自分でつくるプログラムなら、全部パブリックにしてもかまいません。プライベートなものは別のクラス(のオブジェクト)で使えないので、はじめはとても不便な感じがします(入門6の注を見てください)し、そもそも自分でつくったクラスなんですから、中身をいじるなと自分に言うのも変な感じです。
しかし、三つ子の魂百まで、とも言います。はじめからオール・パブリックになれると戻れなくなりますよ。たぶん。
それに、だいたい、ちょっと考えるとわかると思うのですが、クラスのすべてのメンバをパブリックにすると、クラスそのものも不要に思えてきます。例えば、クラス「猫」のnameは「猫」の大事な中身だったわけですが、これをパブリックにするくらいなら、最初から、「猫」なんかつくらずにnameだけでよかったのです。入門6の注のプログラムをさらに「改良」する

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string name;
    cout << "猫を生成します。名前を入力してください。" << endl;
    cin >> name;
    cout << "猫が生成されました。"<<endl;  //嘘です。「猫」なんてどこにもいません。
    cout << "その名は" << name << "です。" <<endl;
    cout << "にゃあ。俺様は" << name << "だ。" <<endl;
}

もちろん、目的がこれだけのプログラムならこれが一番です。しかし、もう「猫」はいないのです。後で、猫を使ったプログラムを書こうと思ったら、また、はじめからコードを書かなければいけないのです。
もし、大きなプログラムを(いずれは)書くのなら、まじめに、クラスをつくり、プライベートなメンバを宣言しておくのがよいと思えてきませんでしたか?
とにかく、雰囲気はわかってもらえたのではないでしょうか。
さて、前回の「大魔王とヒーロー」を考えます。くどいですが、同じ事を実行するだけなら、クラスを使わずに書いた方がたぶんもう少し短くなるでしょう。しかし、分業や書き直しを考えると、クラスを書いてプログラムを部品化しておいた方が良いのです。それに、部品をひとつひとつ作って組み上げるという「クラスの発想」になれてくると、プログラミングも楽しくなってきます。だから、クラスを使っているのです。(継承という機能を使えばもう少し「簡単」になるかもしれません。それは乞うご期待。)
今、クラスを書く人が分業しているとしましょう。唐突ですが、Taiketu_basyoのメンバ関数taiketu()なんですが、みなさんはどうおもいますか。私は、この関数を他人様(ひとさまと読む)にいじってほしくはないと、思います。(と、思ったとしましょう。本当はみなさんがどういじろうと勝手です。)そのときは、どうすればよいと思いますか?そうです。taiketu()もプライベートにしてしまえばよいのです。つまり、前回のクラスの宣言を変えて、

class Taiketu_basyo  //対決場所のクラス
{
    Daimao bu;   //対決場所にいる大魔王bu!
    Hero you;    //対決場所にいるヒーローyou!
    int bu_no_basho;   //大魔王のいる場所(1〜5の数値)、これは後で決まる
    int you_no_basho;  //ヒーローのいる場所(1〜5の数値)、これは後でユーザが決める
    void taiketu();   //「ヒーローと大魔王が一度対決する」関数 プライベートにしました!
public:
    Taiketu_basyo();  //対決場所のコンストラクタ、定義はクラス宣言の外で
    void kurikaesi_taiketu();  //「決着がつくまで対決する」関数
};

とします。もちろん、これはこのクラスの設計者の意志であり、みなさんが設計する場合はどうしても自由です。ただ、こうしておくと、main()が

int main()
{
    Taiketu_basyo dokoka;  //対決場所dokokaの生成
                           //ここでコンストラクタが働き、ヒーローと大魔王の位置が決められる。

    dokoka.taiketu();       //dokokaの対決(一度きりバージョン)
}

ではコンパイラがエラーであると言ってきます。プライベート関数taiketu()をクラスの外で(つまり、main()の中で)使おうとしたからです。前回の定義のままなら、これはエラーにはならなかったのです。
なぜ、こうしたかというと、このクラスの設計者である私が、一回きりの対決関数を利用者(これは私のクラスを使う別のプログラマと言う意味です。今の場合、これも私なんですけど、、、。大きなプログラムでは本当に別の人になるわけです。)に使ってほしくなかったからです。そういう設計者の意志の現れなのです。もちろん、この「意志」は単なる「エゴ」ではありません。このようにこのクラスの利用者にtaiketu()の使用を禁じておけば、あとで、この関数を書き換えても誰からも文句がでないはずなのです。
これは冗談ではないのです。あとでtaiketu()をいろいろ書き換えたくなることもあるでしょう。このとき、利用者側がtaiketu()を使っていれば、クラスの製作者(設計者)と利用者が相談しなければ変更はできないはずです。しかし、プライベート宣言によって、利用者に使用を禁じておけば、クラスの製作者が自分の責任で自由に書き換えられるのです。これこそが、プログラムの部品化であり、プライベートがあるもっとも重要な理由なのです。(なんか、今日はずいぶんうまく説明できたような気がするのは、私だけでしょうか?)
クラスを利用しようとする人は、クラスのコードをすべて見る必要はないのです。(全部見て、全部理解するなら、はじめから自分でつくるのとそれほど差はないでしょう。)利用者は、まず、クラスの宣言を見て、どの関数がパブリックなものか(実はパブリックなデータもあります)を知り、その使い方を理解し、あとはただそのクラスを使えばよいのです。プライベートなものに手をだすことは、危険ですし、また約束違反です。

クラスの宣言とは

 仕様書であり、また、製作者と利用者との契約

なのです。(きまった〜。かっちょいー。精神年齢は12歳。と、昔書いたな。


目次のページ
前のページ 次のページ