見出し画像

C++ 再入門 その9 公開と非公開

(C++もそうですが)C言語で関数の中で宣言したローカル変数を当たり前のように使いますが、この変数を関数の外から読み書きできたりすると、ちょっと困ったことになることがあります。一般的なローカル変数は関数に入るたびに作られ出れば捨てられるので外から使いようがないのですが、関数内で宣言された static 変数なんかが該当します。

クラシックなBASICなどにはローカル変数が無かったので、サブルーチン内で「のみ」使う変数だと思っていると、他のサブルーチンでこっそり使われていたりするというのも特別なことではありませんでした。もちろん、うっかり「同じ名前」を使ってしまっただけの事故もあります。そうなると次にサブルーチンを呼んだ時に変数に想定している値が入っていなかったり、サブルーチンを修正して該当する変数の名前を変えたり、もう使わなくなったりして消してしまうと、こっそり読んでいた方のサブルーチンが動かなくなってしまう訳です。C言語だってすべてグローバル変数で記述すれば同じなんで想像はつきますよね。

さてクラスに戻るとメンバ変数と呼ばれるクラスで宣言される変数は、そのクラスの変数を作れば変数を経由していつでも読み書きできます。それはクラスの public:(公開) という部分で宣言されているからです。このような書き方でメンバ変数を宣言すれば、そのクラスの変数から見ればクラスの中では自由に読み書きできる限定的なグローバル変数という使い方が出来るわけですね。

勘違いしないように補足しておくと、A というクラスを定義して、このクラスの変数 c1 と c2 を宣言した場合、この2つの変数は別の変数ですから、c1 と c2 のメンバ変数は別の変数です。ですから、メンバ変数の名前は同じでも、それぞれ値を持ちますからね(もちろん構造体でも同じ話)。

#include <iostream>
using namespace std;

class A {
public:
  int a;
  int b;
};

int main() {
  A c1;
  A c2;

  c1.a = 1;
  c1.b = 2;
  c2.a = 3;
  c2.b = 4;

  cout << "c1:" << c1.a << "," << c1. b << endl;
  cout << "c2:" << c2.a << "," << c2.b << endl;
}

c1:1,2
c2:3,4

サンプルコードの出力

さてメンバ変数の中にはクラスの中でのローカル変数みたいな使い方をする変数もあります。例えばキューのようなデータを持っている場合、いろいろなクラスに属する関数からアクセスする必要があるのでメンバ変数として宣言するのが普通です。ところが、このキューが public: だと、クラスの関数以外の方法でもキューを覗いたり、書き換えてしまうことが出来てしまいます。これはちょっと都合が悪いわけです。そこでC++には、クラスの関数の中でしか有効にならない private: (非公開)という書き方が出来ます。※main()からbを読み書きしようとするとコンパイルエラー。

#include <iostream>
using namespace std;

class A {
public:
  int a;
private:
  int b;
};

int main() {
  A c1;
  A c2;

  c1.a = 1;
  c2.a = 2;

  cout << "c1:" << c1.a << endl;
  cout << "c2:" << c2.a << endl;
}

c1:1
c2:2

サンプルコードの出力

このように private: の後に変数宣言を書けば、その変数にはクラスに属する関数からしかアクセスすることが出来ません。変数を経由して使おうとしても、その変数は見えません(当然コンパイルエラー)。実は変数だけではなく関数を private: にすることも出来て、この場合は同じクラスに所属する関数からしか呼び出すことが出来なくなります。クラスの中での共通処理を書く場合には良く使います。

ちなみに public: と private: は宣言の中に何度現れても良く順序も決まっていません。また、このようなアクセス制御構文は他に protected: というのがあるのですが、それはクラスの継承の時に登場します。

さて、どの変数を公開(public)にして、どの変数を非公開(private)にするのか悩むこともあるでしょうが実はメンバ変数は原則としてすべて非公開にするのが普通です。中にはクラスの外から読み書きしたい変数だってありますよね。そういった場合にはメンバ変数を読んだり書いたりするクラスの関数を用意するのです。

#include <iostream>
using namespace std;

class A {
public:
  int a;
  void set(int i) { b = i; }
  int get(void) { return b; }
private:
  int b;
};

int main() {
  A c1;

  c1.a = 1;
  c1.set(2);

  cout << "c1:" << c1.a << "," << c1.get() << endl;
}

c1:1,2

サンプルコードの出力

このようにメンバ変数bを非公開にしても、公開されているクラスの関数set()とget()を使うことで、bを読み書きすることが出来ます。

カンの良い人は気が付きましたね。こうすることで、メンバ変数の値を読むことは出来るけど書くことはできないようにしたり(setを書かない、もしくは private にする)、値を設定する時に「有効な値」であるかをチェックするコードを忍ばせることが出来るようになるわけです。また標準的な値があるのであれば、setにデフォルト引き数を用意するなんてことも可能です。このように変数を読み書きするための関数を「アクセッサ」と呼ぶこともあります。

これだけでも構造体に比べれば、なかなか便利な使い方が出来ます。「クラスというのはオブジェクトであって…」云々という面倒な事を考えなくても、C++の機能を、その一部でも使ってみれば良いのです。こうしてC++のやり方に馴染んでいけば気がつけばオブジェクト使いになっていたりするものです。

C++ の基礎 : アクセス制限

ヘッダ画像は、以下のものを使わせていただきました。
https://commons.wikimedia.org/wiki/File:ISO_C%2B%2B_Logo.svg
Jeremy Kratz - https://github.com/isocpp/logos, パブリック・ドメイン, https://commons.wikimedia.org/w/index.php?curid=62851110による

#Cプラスプラス #公開 #非公開 #public #private #アクセッサ #隠蔽 #プログラミング言語 #プログラミング  

いいなと思ったら応援しよう!