アクセス修飾子

クラス内部では、どのメンバー関数も名前によって同一クラスの他のメンバーを直接参照できます。

アクセス修飾子はメンバー宣言に付けるオプションの接頭辞で、プログラムの他のコードから当該メンバーにアクセス可能かどうかを制限します。型やメソッド名の前に記述します。

フィールド

アクセス修飾子 型 フィールド名

メソッド

アクセス修飾子 戻り値型 メソッド名()
{
    ...メソッド本体
}

5種類のアクセスレベル

  1. private プライベート
  2. public パブリック
  3. protected プロテクテッド
  4. internal インターナル
  5. protected internal プロテクテッドインターナル

まずは private と public だけ学習してください。残りについては後続の講座で解説します。

クラス内部では、修飾子に関係なくすべてのメンバーにアクセス可能です

例を見てみましょう

class Robot
{
    public string name;

    int age;

    public void SayHello()
    {
        Console.WriteLine($"Hello everyone my name is {name},I come from Foxdevelop.com");
        Console.WriteLine($"I am {age} years old");
    }

    void AgeUpdate()
    {
        age =  age+1;
    }

    void SayHi()
    {
        SayHello();
    }
}Code language: C# (cs)

上記の例から確認できる通り、public の SayHello、private の AgeUpdate や SayHi、private の age、public の name いずれも、クラス内部に記述されたコードからは相互にアクセスできます。

注意点として、相互呼び出しを記述すると無限ループが発生します。例えば次のコードです。

class Robot
{
    public string name;

    int age;

    public void SayHello()
    {
        Console.WriteLine($"Hello everyone my name is {name},I come from Foxdevelop.com");
        Console.WriteLine($"I am {age} years old");
        SayHi();
    }

    void AgeUpdate()
    {
        age =  age+1;
    }

    void SayHi()
    {
        SayHello();
    }
}Code language: C# (cs)

このコードでは SayHi が SayHello を呼び出し、SayHello が SayHi を呼び出すため、無限再帰ループに陥ります。

最終的にプログラムがクラッシュします

メモリオーバーフローのエラーが表示されます

また、フィールド初期化時に通常のメソッドを直接呼び出すことはできません。静的メソッドのみ利用可能です。インスタンスメソッドはオブジェクトの実体を介して呼び出す必要があるためです。

class Robot
{
    public string name;

    int age = GetInt();

    static int GetInt()
    {
        return 1;
    }

    public void SayHello()
    {
        Console.WriteLine($"Hello everyone my name is {name},I come from Foxdevelop.com");
        Console.WriteLine($"I am {age} years old");
    }

    void AgeUpdate()
    {
        age =  age+1;
    }

    void SayHi()
    {
        SayHello();
    }
}Code language: C# (cs)

上図のようにメソッドを静的に定義すれば利用可能です。ただし age に代入する際、GetInt の戻り値が可変する場合に注意が必要です

class Program
{
    static void Main(string[] args)
    {
        Robot robot1 = new Robot();
        for (int i = 0; i < 100; i++)
        {
            robot1.WriteAge();
            System.Threading.Thread.Sleep(1000);
        }
    }
}

class Robot
{
    public string name;

    int age = GetInt();

    static int GetInt()
    {
        return DateTime.Now.Second;
    }

    public void WriteAge()
    {
        Console.WriteLine($"I am {age} years old");
    }
}Code language: C# (cs)

上記コードでは GetInt が現在時刻の秒数を返します。Main 内の for ループで100回年齢出力メソッドを実行し、出力毎に1秒待機します。実行すると次の現象が確認できます

出力される秒数は初期化時に取得した値のまま変化しません。age の初期化時に GetInt が実行され、例えば45秒が取得されると、age は45で固定され、何度出力しても値は変わりません。これは前回の章で解説した通り、フィールドの初期値は初期化時点で確定する必要があるためです。

ここでアクセス修飾子の話に戻ります

まとめると、修飾子に関係なくクラス内部からはすべてのメンバーにアクセス可能です。

private プライベートアクセス

プライベートメンバーは宣言されたクラス内部からのみアクセス可能で、他のクラスから読み書きすることはできません。

クラスメンバーの既定のアクセスレベルは private です。修飾子を省略した場合と private を明示した場合の意味は完全に同一です。

int MyInt1;              // 暗黙的プライベート(既定)
private int MyInt2;      // 明示的プライベートCode language: C# (cs)

public パブリックアクセス

インスタンスのパブリックメンバーはプログラム内のすべてのオブジェクトからアクセスできます。public 修飾子を手動で記述して宣言する必要があります。

public int MyInt;        // public アクセス修飾子付きCode language: C# (cs)

メンバー可視性ルール

クラスの構造を図で表現する際、クラス図がよく使われます

クラス全体を四角い枠で表し、メンバーは枠内の区画として記載します;

private メンバー:完全にクラスの枠内に収まり外部からは見えない;

public メンバー:一部がクラスの枠の外へ伸び、全体からアクセス可能であることを示します。

class Program
{
    int Member1;         // implicit private
    private int Member2; // explicit private
    public int Member3;  // public
}Code language: C# (cs)

本章のサンプルコード

class C1
{
    int F1;                // 暗黙的プライベートフィールド
    private int F2;        // 明示的プライベートフィールド
    public int F3;         // パブリックフィールド

    void DoCalc()          // 暗黙的プライベートメソッド
    {
        ...
    }

    public int GetVal()    // パブリックメソッド
    {
        ...
    }
}Code language: C# (cs)
  1. プライベートメンバー(F1、F2、DoCalc())C1 クラス内部のコードのみ読み書き・呼び出し可能、外部クラスからは完全に不可視;
  2. パブリックメンバー(F3、GetVal()):プログラム内の任意のクラス・オブジェクトから制限なくアクセス可能;
  3. クラス内部ルールC1 自身のすべてのメソッドは公開・非公開を問わず、同一クラスのすべてのフィールド、メソッドにアクセスできます。

実行可能なサンプル


class Program
{
    static void Main(string[] args)
    {
        Worker worker = new Worker();
        Console.WriteLine(worker.GetHours()); // 正常。クラス外から公開メンバー GetHours にアクセス可能
        Console.WriteLine(worker.ReadSavings());//エラー。インスタンス名 worker. を使ってもクラス外からプライベートメンバー ReadSavings にアクセス不可

        Console.WriteLine(worker.hours); // 正常。クラス外から公開フィールド hours にアクセス可能
        Console.WriteLine(worker.savings); //エラー。プライベートフィールド savings に外部からアクセス不可
        Console.WriteLine(worker.age); //エラー。プライベートフィールド age に外部からアクセス不可
    }
}

class Worker
{
    int age;                // 暗黙的プライベートフィールド
    private double savings;        // 明示的プライベートフィールド
    public int hours;         // パブリックフィールド

    void ReadSavings()          // 暗黙的プライベートメソッド
    {
        Console.WriteLine(savings);
    }

    public int GetHours()    // パブリックメソッド
    {
        return hours;
    }
}Code language: C# (cs)

これでアクセス修飾子について基礎的な理解が得られたはずです。

アクセス修飾子

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です