2006-06-08
前回、メンバ関数というのは、それが属している構造体のデータメンバ(フィールド)を操作するための関数だと書きました。しかし、実際には、構造体のデータメンバの操作は、メンバ関数でなくても、構造体へのポインタさえ引数として渡せば、どんな関数でもできてしまいます。
このように、どこからでも構造体のデータメンバを操作できるようにしていると、グローバル変数が抱える問題と同じようなことが、構造体のデータメンバにも発生するわけです。そこで、メンバ関数以外からデータメンバを操作できる方法があると、そのような問題はなくなります。これは、ある意味で、オブジェクトの宣言時にstaticを付けて内部結合にするのと似たところがあります。
同様に、メンバ関数からしか呼び出されないメンバ関数というのもあってよいわけです。これも、staticを付けて内部結合にされた関数と似たところがあります。このように、メンバ関数以外からの操作を禁止したり、許可したりするのがアクセス制御です。
メンバ以外のオブジェクトや関数は、staticやexternといった記憶クラス指定子を使って、翻訳単位の外部からのアクセスを制御しますが、構造体の外部からのアクセスを制御するには「アクセス指定子」という、C++特有のキーワードを使用します。
アクセス指定子には、次の3種類があります。
- public
- 構造体の外部からでも自由にアクセスできる。
- protected
- 構造体のメンバ関数、および派生した構造体のメンバ関数からのみアクセスできる。
- private
- その構造体のメンバ関数からのみアクセスできる。
このうち、protectedに関しては、機会を改めて詳しく説明したいと思います。今回は、上記のうち、publicとprivateに限って説明することにします。
構造体の場合、アクセス指定子を何も使わなければ、デフォルトでpublicが指定されたのと同じ意味になります。すなわち、メンバ関数だけでなく、全く関係のないところからでも、自由にメンバを操作することができるわけです。これに対して、
struct A
{
int func(int arg);
private:
int value;
};
のようにprivateアクセス指定子を使うと、構造体の宣言が終わるか、他のアクセス指定子が現れるまでの間に記述されたメンバは、privateということになります。ここでは、valueがprivateなメンバになっています。
このようにすることで、データメンバvalueは、メンバ関数func以外からアクセスされることがなくなります。もちろん、A型へのポインタをint*型などにキャストして、無理やりアクセスすることは可能ですが、そうした行為は反則のようなものです。
アクセス制御を適切に使用することで、構造体のデータメンバと、その操作を行うメンバ関数を一まとめにして管理しやすくなります。データメンバは、メンバ関数を介してしか操作されませんから、堅牢な設計が可能になるのです。
以上は建前です。現実の開発現場では、このアクセス制御の意味を十分に理解していないブログラマが多数存在することも事実です。彼らは、とにかくコンパイルを通し、動作させるという大義名分の前には、躊躇なくアクセス指定子をコメントアウトしたり、記述位置をずらしたりします。
このようなアクセス制御の変更は、よほど注意深くやらないと、単に設計上の安全装置を外すだけの暴挙になってしまいます。例えるなら、アクセス制御を勝手に変更したソースコードは、免疫機能が破壊され、AIDSに犯されたような状態になってしまうわけです。
Comment