アクセス指定子


概要

アクセス指定子とはクラスのメンバに対しての公開範囲を設定できる機能で、
「public」「private」「protected」の3種類があります。
この機能を使用することで、外部からアクセスを制限したり、
継承先で継承元のメンバを使用できるようにしたりできます。
アクセス指定子の公開範囲は以下の通りです。

cpp_0003

指定方法

public、private、protectedの指定方法は共通しており、
クラス内のアクセス制御を行いたいメンバの前で宣言を行います。
アクセス指定子の有効範囲は指定した次の行から
次のアクセス指定子の指定があるまで継続します。
※何も指定がなかった場合、メンバは「private」として扱われます。
		
// 書式
class Employee
{
アクセス指定子1:
	メンバ関数

アクセス指定子2:
	メンバ変数
};

// 具体例
class Employee
{
public:
	// 社員情報表示
	void ShowInfo();

private:
	int Number; 	// 社員番号
	char Name[32];	// 名前
	int Salary;	// 給料
};

上の具体例ではShowInfoがpublic、Number、Name、Salaryがprivateです。

public

public指定をされたメンバはクラスの中と外の両方で使用可能です。

class Employee
{
public:
	int Number; 		// 社員番号

	void ShowInfo();
};

void Employee::ShowInfo()
{
	printf("社員番号 = %d\n", Number);
}

void main()
{
	Employee suzuki;

	suzuki.Number = 1001;
}

上のコードから分かるようにpublic指定されたメンバは
インスタンス化したクラスからもアクセスが可能です。

private

private指定をされたメンバはそのクラス内でしか使用できませんclass Employee
{
public:
	void Init();

private:
	int Number; 	// 社員番号
};

void Employee::Init()
{
	Number = 1001;	// 自分のクラス内名ので変更はOK
}

void main()
{
	Employee suzuki;

	suzuki.Init();
	suzuki.Number = 1002; // エラー
}

上のコードのようにインスタンス化したEmployeeクラスのsuzukiの
Numberを外部(main関数)から変更しようした場合はエラーになり、
EmployeeのInit(自分のメンバ関数)から変更した場合は問題なく変更できます。

protected

protectedの効果は基本的にprivateと同じで、クラス内でしか使用できません。
ただ、privateと異なる点として「継承」を使用した場合継承先でも使用可能です。
※protectedは継承のページでも再度記述しています。

class Employee
{
public:
	Employee(int number, int salary);
protected:
	int Number; 	// 社員番号

private:
	int Salary;	// 給与
};

Employee::Employee(int number, int salary)
{
	Number = number;
	Salary = salary;
}

class Manager : public Employee
{
public:
	Manager(int number, int salary);
	void ShowInfo();
};

Manager::Manager(int number, int salary) :
		Employee(number, salary)
{
}

void Manager::ShowInfo(void)
{
	printf("社員番号 => %d\n", Number);	// protectedなので継承先でも使える
	printf("給与 => %d\n", Salary);		// privateなので継承先では使えない
}

void main(void)
{
	Manager sato(1002, 340000);
	sato.Salary = 1003;		// 外部からはアクセスできないのでエラー
	sato.ShowInfo();
}

上のコードのようにprotectedを使うと外部からのアクセスはできませんが、
宣言をしたクラスや継承先で自由に使用することができます。

アクセサ

アクセサとは外部からアクセスすることができないメンバ変数に
アクセスするためのメンバ関数のことです。

アクセサがある理由

privateやprotected設定がされているメンバは外部からのアクセスを遮断しています。
しかし、その値を参照、または変更しなければいけない状況がでます。
この時、privateをpublicにしたら、様々なところでアクセスが可能となり、
保守性(メンテナンス性)が損なわれることになります。
そこでメンバに間接的にアクセスできる関数を用意して参照や変更をできるようにし、
最低限の保守性を保ちます。

アクセサの基本

アクセサには参照用の「ゲッター(getter)」と変更用の「セッター(setter)」があります。
命名や定義内容は一般的によく使われている方法がありますので、そちらを紹介します。

命名

アクセサの名前はゲッターなら「Get or get変数名」セッターなら「Set or set変数名」とつけます。


class Employee
{
public:
	int GetNumber();
	void SetNumber(int number);

private:
	int Number;
};

もし、変数名に「m_」などのプレフィックスが設定されている場合は
プレフィックスを取り除いた名前を使用することが多いです。

class Employee
{
public:
	// どちらもm_はつけない
	int GetNumber();
	void SetNumber(int number);

private:
	int m_Number;
};

定義

アクセサの定義はゲッターはメンバの値を戻り値としてreturnでメンバを返すだけ、
セッターはメンバと同じ型の引数を一つ指定して、その値をメンバに代入するだけです。

// ゲッターの書式
メンバの型 Getメンバ名()
{
	return メンバ;
}

// セッターの書式
void Setメンバ名(メンバと同じ型 値)
{
	メンバ = 値;
}

// 具体例
class Employee
{
public:
	int GetNumber()
	{
		return Number;
	}

	void SetNumber(int number)
	{
		Number = number;
	}

private:
	int Number;
};

アクセサはどのメンバでも上のコードのように一行で終わるので
インラインとしてクラス内に定義することが多いです。

アクセサの注意点

アクセサはアクセス拒否しているメンバに対して外部からのアクセスを可能とする
便利な方法ですが、多用することはできるだけ避けて、
使用しないようにするにはどうすればいいかを考えるようにしてください。
結局のところ、アクセサはpublic指定を行っていることと同じ問題を抱えます。
セッターは外部からのアクセスが発生するので、バグの温床となり、
ゲッターでポインタなどを返すと、値を取得した人が
絶対に変更を掛けないとも限りません。

そういったことを起こさないようにすることが大切なので、
アクセサを使用しなくても済むような設計、開発を目指してください。