名前空間
変種
操作

アクセス指定子

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (C++20未満)
noexcept 指定子 (C++11)
例外
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
アクセス指定子
friend 指定子
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

クラス/構造体または共用体member-specification において、後続のメンバのアクセス可能性を定義します。

派生クラスの宣言の base-specifier において、後続の基底クラスの継承メンバのアクセス可能性を定義します。

目次

[編集] 構文

public : member-declarations (1)
protected : member-declarations (2)
private : member-declarations (3)
public base_class (4)
protected base_class (5)
private base_class (6)
1) 指定子の後に宣言されるメンバはパブリックメンバアクセスを持ちます。
2) 指定子の後に宣言されるメンバはプロテクテッドメンバアクセスを持ちます。
3) 指定子の後に宣言されるメンバはプライベートメンバアクセスを持ちます。
4) パブリック継承。 指定子の後に記載された基底クラスのパブリックおよびプロテクテッドメンバは派生クラス内でそのメンバアクセスを維持します。
5) プロテクテッド継承。 指定子の後に記載された基底クラスのパブリックおよびプロテクテッドメンバは派生クラスのプロテクテッドメンバになります。
6) プライベート継承。 指定子の後に記載された基底クラスのパブリックおよびプロテクテッドメンバは派生クラスのプライベートメンバになります。

[編集] 説明

すべてのクラスメンバ (静的、非静的、関数、型、など) の名前は、関連付けられた「メンバアクセス」を持ちます。 メンバの名前がプログラムのどこかで使用されるとき、そのアクセスがチェックされ、それがアクセスルールを満たさない場合、そのプログラムはコンパイルできません。

#include <iostream>
class Example {
 public: // この地点より後のすべての宣言はパブリックです。
    void add(int x) { // メンバ「add」はパブリックアクセスを持ちます。
        n += x; // OK、プライベートな Example::n は Example::add からアクセスできます。
    }
 private: // この地点より後のすべての宣言はプライベートです。
    int n = 0; // メンバ「n」はプライベートアクセスを持ちます。
};
int main()
{
    Example e;
    e.add(1); // OK、パブリックな Example::add は main からアクセスできます。
//  e.n = 7;  // エラー、プライベートな Example::n は main からアクセスできません。
}


アクセス指定子はどのクラスメンバがクラスの使用者からアクセス可能であるか (すなわちインタフェース) およびどのメンバがクラスの内部使用のためであるか (すなわち実装) を決定する能力をクラスの作者に与えます。

[編集] 詳細

クラスのすべてのメンバ (メンバ関数の本体、メンバオブジェクトの初期化子、およびネストしたクラス定義全体) が、クラスがアクセスできるすべての名前へのアクセスを持ちます。 メンバ関数内のローカルクラスは、そのメンバ関数がアクセスできるすべての名前へのアクセスを持ちます。

キーワード class を用いて定義されたクラスは、そのメンバおよびその基底クラスに対して、デフォルトでプライベートアクセスを持ちます。 キーワード struct を用いて定義されたクラスは、そのメンバおよびその基底クラスに対して、デフォルトでパブリックアクセスを持ちます。 union はそのメンバに対してデフォルトでパブリックアクセスを持ちます。

プロテクテッドまたはプライベートメンバへのアクセスを追加の関数またはクラスに許可するために、フレンド宣言を使用することができます。

アクセス可能性はその起源と無関係にすべての名前に適用されるため、 typedef または using 宣言によって導入された名前はチェックされ、その参照先の名前はチェックされません。

class A : X {
  class B { }; // B はプライベートです。
public:
  typedef B BB; // BB はパブリックです。
};
void f() {
  A::B y; // エラー、 A::B はプライベートです。
  A::BB x; // OK、 A::BB はパブリックです。
}

メンバアクセスは可視性に影響しません。 プライベートなメンバおよびプライベート継承したメンバの名前は可視である、オーバーロード解決で考慮される、アクセス不可能な基底クラスへの暗黙の変換は未だ考慮される、などです。 メンバアクセスのチェックはあらゆる与えられた言語要素が解釈された後の最後のステップです。 このルールの意図は、いかなる privatepublic に置き換えてもプログラムの動作を決して変えないことです。

デフォルト関数引数およびデフォルトテンプレート引数で使用される名前に対するアクセスチェックは、使用の時点ではなく、宣言の時点で行われます。

仮想関数の名前に対するアクセスルールは、呼び出しの地点で、メンバ関数が呼ばれるオブジェクトを表すために使用される式の型を用いて、行われます。 最終オーバーライダーのアクセスは無視されます。

struct B { virtual int f(); }; // f は B 内ではパブリックです。
class D : public B { private: int f(); }; // f は D 内ではプライベートです。
void f() {
 D d;
 B& b = d;
 b.f(); // OK、 B::f() はパブリックです。 たとえプライベートでも D::f() が呼ばれます。
 d.f(); // エラー、 D::f() はプライベートです。
}

無修飾の名前探索ではプライベートな名前が修飾付き名前探索を通してアクセス可能である場合もあります。

class A { };
class B : private A { };
class C : public B {
   A* p; // エラー、無修飾の名前探索は B のプライベートな基底としての A を発見します。
   ::A* q; // OK、修飾付き名前探索は名前空間レベルの宣言を発見します。
};

継承グラフ内で複数の経路を通してアクセス可能な名前は、最もアクセスを持つ経路のアクセスを持ちます。

class W { public: void f(); };
class A : private virtual W { };
class B : public virtual W { };
class C : public A, public B {
void f() { W::f(); } // OK、 W は B を通して C からアクセス可能です。
};

任意個のアクセス指定子が任意の順序でクラス内に現れることができます。 メンバアクセス指定子はクラスのレイアウトに影響することがあります。 非静的データメンバのアドレスは同じアクセスを持つメンバについて宣言の順序で増加することのみが保証されます。 StandardLayoutType の場合はすべての非静的データメンバが同じアクセスを持たなければなりません。

メンバが同じクラス内で再宣言されるときは、同じメンバアクセスの下で行われなければなりません。

struct S {
  class A; // S::A はパブリックです。
private:
  class A {}; // エラー、アクセスを変えることはできません。
};

[編集] パブリックメンバアクセス

パブリックメンバはクラスの公開インタフェースの一部を形成します (公開インタフェースの他の部分は ADL によって発見される非メンバ関数です)。

クラスのパブリックメンバはどこからでもアクセス可能です。

class S {
 public: // n、f、E、A、B、C、U はパブリックメンバです。
    int n;
    static void f() {}
    enum E {A, B, C};
    struct U {};
};
int main()
{
    S::f(); // S::f は main からアクセス可能です。
    S s;
    s.n = S::B; // S::n および S::B は main からアクセス可能です。
    S::U x; // S::U は main からアクセス可能です。
}

[編集] プロテクテッドメンバアクセス

プロテクテッドメンバは派生クラスに対するインタフェースを形成します (これはクラスの公開インタフェースとは区別されます)。

クラス Base のプロテクテッドメンバは以下からのみアクセスできます。

1) Base のメンバおよびフレンド。
2) Base から派生したあらゆるクラスのメンバおよびフレンド (C++17未満)。 ただし Base から派生した型のオブジェクト (this を含みます) に対する操作のときだけです。
struct Base {
 protected:
    int i;
 private:
    void g(Base& b, struct Derived& d);
};
 
struct Derived : Base {
    void f(Base& b, Derived& d) // 派生クラスのメンバ関数。
    {
        ++d.i; // OK、 d の型は Derived です。
        ++i; // OK、暗黙の「*this」の型は Derived です。
//      ++b.i; // エラー、 Base を通してプロテクテッドメンバにアクセスすることはできません。
//                 (さもなければ Derived2 のような別の派生クラスの
//                  基底の実装を変更できてしまいます)
    }
};
 
void Base::g(Base& b, Derived& d) // Base のメンバ関数。
{
    ++i; // OK。
    ++b.i; // OK。
    ++d.i; // OK。
}
 
void x(Base& b, Derived& d) // 非メンバ、非フレンド。
{
//    ++b.i; // エラー、非メンバからアクセスできません。
//    ++d.i; // エラー、非メンバからアクセスできません。
}

プロテクテッドメンバへのポインタが形成されるときは、その宣言で派生クラスを使用しなければなりません。

struct Base {
 protected:
    int i;
};
 
struct Derived : Base {
    void f()
    {
//      int Base::* ptr = &Base::i;    // エラー、 Derived を用いて表さなければなりません。
        int Base::* ptr = &Derived::i; // OK。
    }
};

[編集] プライベートメンバアクセス

プライベートメンバはクラスの実装およびクラスの他のメンバに対するプライベートインタフェースを形成します。

クラスのプライベートメンバは、そのメンバが同じインスタンスのものか異なるインスタンスのものかにかかわらず、そのクラスのメンバおよびフレンドからのみアクセスできます。

class S {
 private:
    int n; // S::n はプライベートです。
 public:
    S() : n(10) {} // this->n は S::S からアクセス可能です。
    S(const S& other) : n(other.n) {} // other.n は S::S からアクセス可能です。
};

明示的なキャスト (C スタイルおよび関数スタイル) は、派生の左辺値からそのプライベート基底の参照へのキャスト、または派生のポインタからそのプライベート基底のポインタへのキャストを許容します。

[編集] 継承

パブリック継承、プロテクテッド継承、およびプライベート継承の意味については派生クラスを参照してください。