メンバー アクセス コントロール (C++)
アクセスの制御を使用すると、クラスの public
インターフェイスを、private
実装の詳細や、派生クラスでのみ使用する protected
メンバーから分離できます。 アクセス指定子は、その後で宣言されたすべてのメンバーに対して当てはまり、これは、次のアクセス指定子が検出されるまで続きます。
class Point
{
public:
Point( int, int ) // Declare public constructor.;
Point();// Declare public default constructor.
int &x( int ); // Declare public accessor.
int &y( int ); // Declare public accessor.
private: // Declare private state variables.
int _x;
int _y;
protected: // Declare protected function for derived classes only.
Point ToWindowCoords();
};
既定のアクセスは、クラスでは private
、構造体または共用体では public
です。 クラスのアクセス指定子は、任意の順序で何回でも使用できます。 クラス型のオブジェクトに対するストレージの割り当ては、実装に依存します。 ただし、コンパイラは、アクセス指定子間で、連続的な高いメモリ アドレスへのメンバーの割り当てを保証する必要があります。
メンバー アクセス コントロール
アクセスの種類 | 意味 |
---|---|
private |
private として宣言されたクラス メンバーは、そのクラスのメンバー関数とフレンド (クラスまたは関数) のみが使用できます。 |
protected |
protected として宣言されたクラス メンバーは、そのクラスのメンバー関数とフレンド (クラスまたは関数) が使用できます。 また、そのクラスから派生したクラスも "protected" メンバーを使用できます。 |
public |
public として宣言されたクラス メンバーは、どの関数からでも使用できます。 |
アクセス制御により、不適切な方法でオブジェクトを使用するのを防ぐことができます。 明示的な型変換 (キャスト) を実行すると、この保護機能が働かなくなります。
Note
アクセス制御は、すべての名前 (メンバー関数、メンバー データ、入れ子のクラス、列挙子) に同等に適用できます。
派生クラスのアクセス コントロール
派生クラスでアクセスできる基底クラスのメンバーは、次の 2 つの要因によって制御されます。派生クラスの継承メンバーに対するアクセスも、この同じ要因によって制御されます。
派生クラスが
public
アクセス指定子を使用して基本クラスを宣言するかどうか。基底クラスでメンバーへのアクセスがどのように指定されているか。
次の表は、これらの要因間の相互作用と、基底クラスのメンバーへのアクセスがどのように決定されるかを示しています。
基底クラスのメンバー アクセス
private |
protected |
public |
---|---|---|
派生アクセスで常にアクセスできない | private 派生を使用する場合は派生クラス内で private |
private 派生を使用する場合は派生クラス内で private |
protected 派生を使用する場合は派生クラス内で protected |
protected 派生を使用する場合は派生クラス内で protected |
|
public 派生を使用する場合は派生クラス内で protected |
public 派生を使用する場合は派生クラス内で public |
次の例は、アクセスの派生を示しています。
// access_specifiers_for_base_classes.cpp
class BaseClass
{
public:
int PublicFunc(); // Declare a public member.
protected:
int ProtectedFunc(); // Declare a protected member.
private:
int PrivateFunc(); // Declare a private member.
};
// Declare two classes derived from BaseClass.
class DerivedClass1 : public BaseClass
{
void foo()
{
PublicFunc();
ProtectedFunc();
PrivateFunc(); // function is inaccessible
}
};
class DerivedClass2 : private BaseClass
{
void foo()
{
PublicFunc();
ProtectedFunc();
PrivateFunc(); // function is inaccessible
}
};
int main()
{
DerivedClass1 derived_class1;
DerivedClass2 derived_class2;
derived_class1.PublicFunc();
derived_class2.PublicFunc(); // function is inaccessible
}
DerivedClass1
では、メンバー関数 PublicFunc
は public
メンバーであり、BaseClass
が public
基底クラスであるため、ProtectedFunc
は protected
メンバーになります。 PrivateFunc
は BaseClass
に対して private
であるため、派生クラスからはアクセスできません。
DerivedClass2
では、BaseClass
が private
基底クラスであるため、PublicFunc
関数と ProtectedFunc
関数は、private
メンバーと見なされます。 繰り返しになりますが、PrivateFunc
は BaseClass
に対して private
であるため、派生クラスからはアクセスできません。
基底クラスにアクセス指定子を使用しなくても、派生クラスを宣言できます。 このような場合、派生クラスの宣言に class
キーワードが使用されていれば、派生は private
と見なされます。 派生クラスの宣言に struct
キーワードが使用されていれば、派生は public
と見なされます。 コード例を次に示します。
class Derived : Base
...
は以下に匹敵します。
class Derived : private Base
...
同様に、
struct Derived : Base
...
は以下に匹敵します。
struct Derived : public Base
...
関数や派生クラスは、基底クラスで friend
宣言を使用して宣言されていない限り、private
アクセスを持つように宣言されたメンバーにアクセスできません。
union
型には基底クラスは設定できません。
Note
private 基底クラスを指定する場合は、派生クラスのユーザーにメンバー アクセスがわかるように、private
キーワードを明示的に使用することをお勧めします。
アクセス制御と静的メンバー
基底クラスを private
として指定した場合、非静的メンバーにのみ影響します。 パブリックな静的メンバーは、派生クラス内でもアクセスできます。 ただし、ポインター、参照、またはオブジェクトを使用して基底クラスのメンバーにアクセスするには、アクセス制御を再び適用する変換が必要になる場合があります。 次の例を考えてみましょう。
// access_control.cpp
class Base
{
public:
int Print(); // Nonstatic member.
static int CountOf(); // Static member.
};
// Derived1 declares Base as a private base class.
class Derived1 : private Base
{
};
// Derived2 declares Derived1 as a public base class.
class Derived2 : public Derived1
{
int ShowCount(); // Nonstatic member.
};
// Define ShowCount function for Derived2.
int Derived2::ShowCount()
{
// Call static member function CountOf explicitly.
int cCount = ::Base::CountOf(); // OK.
// Call static member function CountOf using pointer.
cCount = this->CountOf(); // C2247: 'Base::CountOf'
// not accessible because
// 'Derived1' uses 'private'
// to inherit from 'Base'
return cCount;
}
このコードでは、アクセス制御により、Derived2
へのポインターから Base
へのポインターへの変換が禁止されます。 this
ポインターは暗黙的に型 Derived2 *
です。 CountOf
関数を選択するには、this
を Base *
型に変換する必要があります。 Base
は Derived2
に対する private 間接基底クラスであるため、このような変換は許可されません。 private 基底クラス型への変換は、直接の派生クラスへのポインターにのみ使用できます。 したがって、型 Derived1 *
のポインターは型 Base *
に変換できます。
ポインター、参照、またはオブジェクトを使用して選択することなく CountOf
関数を明示的に呼び出すことは、変換を意味しません。 したがって、呼び出しは許可されます。
派生クラス T
のメンバーとフレンドは T
へのポインターを、T
の private 直接基底クラスへのポインターに変換できます。
仮想関数へのアクセス
virtual
関数に適用されるアクセス制御は、関数呼び出しを行う型によって決まります。 関数の宣言のオーバーライドは、特定の型のアクセス制御には影響しません。 次に例を示します。
// access_to_virtual_functions.cpp
class VFuncBase
{
public:
virtual int GetState() { return _state; }
protected:
int _state;
};
class VFuncDerived : public VFuncBase
{
private:
int GetState() { return _state; }
};
int main()
{
VFuncDerived vfd; // Object of derived type.
VFuncBase *pvfb = &vfd; // Pointer to base type.
VFuncDerived *pvfd = &vfd; // Pointer to derived type.
int State;
State = pvfb->GetState(); // GetState is public.
State = pvfd->GetState(); // C2248 error expected; GetState is private;
}
前の例では、型 VFuncBase
へのポインターを使用する仮想関数 GetState
の呼び出しは、VFuncDerived::GetState
を呼び出します。GetState
は public
として扱われます。 ただし、GetState
が VFuncDerived
クラスで private
として宣言されているため、VFuncDerived
型へのポインターを使用して GetState
を呼び出すとアクセス制御違反になります。
注意事項
仮想関数 GetState
は、基底クラス VFuncBase
へのポインターを使用して呼び出すことができます。 これは、呼び出された関数がその関数の基底クラス版であることを意味しません。
多重継承でのアクセス制御
仮想基底クラスを含む多重継承のグリッドでは、任意の名前に複数のパスを通じてアクセスできます。 パスが異なると適用できるアクセス制御も異なるため、コンパイラは最大のアクセスを許可するパスを選択します。 次の図を参照してください。
この図は、次の継承階層を示しています。クラス VBase は基底クラスです。 LeftPath クラスは、仮想 private VBase を使用して VBase から継承します。 クラス RightPath も VBase から継承しますが、仮想 public VBase を使用します。 最後に、クラス Derived は、LeftPath、RightPath を使用して public 、クラス LeftPath とクラス RightPath public の両方から継承します。
継承グラフのパスに沿ったアクセス
図では、クラス VBase
で宣言される名前は、必ずクラス RightPath
経由でアクセスされます。 LeftPath
が VBase
を private
基底クラスとして宣言するのに対し、RightPath
は VBase
を public
基底クラスとして宣言するため、右のパスの方がアクセスが簡単です。
関連項目
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示