Namespaces
Variants

Access specifiers

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Access specifiers
friend specifier

Class-specific function properties
Special member functions
Templates
Miscellaneous

클래스 또는 구조체나 class/struct 또는 union member-specification 에서 후속 멤버들의 접근 가능성을 정의합니다.

파생 클래스 선언의 base-specifier 에서, 후속 기본 클래스의 상속된 멤버 접근성을 정의합니다.

목차

구문

public : 멤버 선언 (1)
protected : 멤버 선언 (2)
private : 멤버 선언 (3)
public 기본 클래스 (4)
protected 기본 클래스 (5)
private 기본 클래스 (6)
1) 접근 지정자 뒤에 선언된 멤버들은 public 멤버 접근 권한을 가집니다.
2) 접근 지정자 뒤에 선언된 멤버들은 protected 멤버 접근 권한을 가집니다.
3) 접근 지정자 뒤에 선언된 멤버들은 private 멤버 접근 권한을 가집니다.
4) Public inheritance : 액세스 지정자 뒤에 나열된 base class 의 public 및 protected 멤버들은 파생 클래스에서 자신들의 멤버 액세스 권한을 유지합니다.
5) Protected inheritance : 접근 지정자 뒤에 나열된 base class 의 public 및 protected 멤버들은 파생 클래스의 protected 멤버가 됩니다.
6) Private inheritance : 액세스 지정자 뒤에 나열된 base class 의 public 및 protected 멤버들은 파생 클래스의 private 멤버가 됩니다.

기본 클래스의 private 멤버들은 public, protected, private 상속에 관계없이 항상 파생 클래스에서 접근할 수 없습니다.

설명

모든 class 멤버(static, non-static, function, type 등)의 이름은 연관된 "멤버 접근 권한"을 가집니다. 프로그램 어디에서든 멤버 이름이 사용될 때, 해당 접근 권한이 검사되며 접근 규칙을 만족하지 않을 경우 프로그램은 컴파일되지 않습니다:

#include <iostream>
class Example
{
public:             // 이 지점 이후의 모든 선언은 public입니다
    void add(int x) // 멤버 "add"는 public 접근 권한을 가짐
    {
        n += x;     // OK: private Example::n은 Example::add에서 접근 가능
    }
private:            // 이 지점 이후의 모든 선언은 private입니다
    int n = 0;      // 멤버 "n"은 private 접근 권한을 가짐
};
int main()
{
    Example e;
    e.add(1); // OK: public Example::add는 main에서 접근 가능
//  e.n = 7;  // 오류: private Example::n은 main에서 접근할 수 없음
}

접근 지정자는 클래스 작성자에게 클래스 사용자(즉, 인터페이스 )가 접근할 수 있는 클래스 멤버와 클래스의 내부 사용을 위한 멤버( 구현 )를 결정할 수 있는 권한을 부여합니다.

상세 설명

클래스의 모든 멤버들( 멤버 함수 의 본문, 멤버 객체의 초기화자, 그리고 전체 중첩 클래스 정의 )은 해당 클래스가 접근할 수 있는 모든 이름에 접근할 수 있습니다. 멤버 함수 내의 지역 클래스는 해당 멤버 함수가 접근할 수 있는 모든 이름에 접근할 수 있습니다.

class 키워드로 정의된 클래스는 기본적으로 해당 멤버와 기본 클래스에 대해 private 접근 권한을 가집니다. struct 키워드로 정의된 클래스는 기본적으로 해당 멤버와 기본 클래스에 대해 public 접근 권한을 가집니다. union 은 기본적으로 해당 멤버에 대해 public 접근 권한을 가집니다.

보호되거나 비공개 멤버에 추가 함수나 클래스의 접근을 허용하기 위해, friendship 선언 을 사용할 수 있습니다.

접근성은 그 출처에 관계없이 모든 이름에 적용되므로, typedef 또는 using 선언 (상속 생성자 제외)으로 도입된 이름이 검사되며, 그것이 참조하는 이름은 검사되지 않습니다:

class A : X
{
    class B {};   // B는 A에서 private입니다
public:
    typedef B BB; // BB는 public입니다
};
void f()
{
    A::B y;  // 오류: A::B는 private입니다
    A::BB x; // OK: A::BB는 public입니다
}

멤버 접근은 가시성에 영향을 주지 않습니다: private 및 private 상속된 멤버들의 이름은 오버로드 해결 시 보여지고 고려되며, 접근 불가능한 기본 클래스로의 암시적 변환은 여전히 고려됩니다. 멤버 접근 검사는 주어진 언어 구조가 해석된 후 마지막 단계에서 수행됩니다. 이 규칙의 의도는 private public 로 교체하더라도 프로그램의 동작이 결코 변경되지 않도록 하는 것입니다.

기본 함수 인수 에서 사용되는 이름들에 대한 접근 검사는 사용 지점이 아닌 선언 지점에서 수행됩니다. 이는 기본 템플릿 매개변수 에서 사용되는 이름들에도 동일하게 적용됩니다.

virtual functions 이름에 대한 접근 규칙은 멤버 함수가 호출되는 객체를 나타내는 데 사용된 표현식의 타입을 사용하여 호출 지점에서 확인됩니다. 최종 오버라이더의 접근 권한은 무시됩니다:

struct B
{
    virtual int f(); // B에서 f는 public
};
class D : public B
{
private:
    int f(); // D에서 f는 private
};
void f()
{
    D d;
    B& b = d;
    b.f(); // OK: B::f는 public, D::f가 private임에도 호출됨
    d.f(); // 오류: D::f는 private
}

한정되지 않은 이름 검색 에 따라 비공개인 이름은 한정된 이름 검색을 통해 접근 가능할 수 있습니다:

class A {};
class B : private A {};
class C : public B
{
    A* p;   // 오류: 비정규화된 이름 조회가 A를 B의 private 기반 클래스로 찾음
    ::A* q; // 정상: 정규화된 이름 조회가 네임스페이스 수준 선언을 찾음
};

상속 그래프에서 여러 경로를 통해 접근 가능한 이름은 가장 접근성이 높은 경로의 접근 권한을 가집니다:

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에서 접근 가능함
    }
};

클래스 내에는 임의의 순서로 임의의 수의 접근 지정자가 나타날 수 있습니다.

멤버 접근 지정자는 클래스 레이아웃 에 영향을 미칠 수 있습니다: 비정적 데이터 멤버의 주소는 선언 순서대로 증가한다는 보장이 접근 지정자로 구분되지 않은 멤버에 대해서만 (C++11까지) 동일한 접근 권한을 가진 멤버에 대해서만 (C++11부터) 적용됩니다.

(C++23까지)

표준 레이아웃 타입 의 경우, 모든 비정적 데이터 멤버는 동일한 접근 권한을 가져야 합니다.

(C++11부터)

동일한 클래스 내에서 멤버가 재선언될 때, 동일한 멤버 접근 권한 아래에서 이루어져야 합니다:

struct S
{
    class A;    // S::A는 public입니다
private:
    class A {}; // 오류: 접근 권한을 변경할 수 없음
};

공개 멤버 접근

Public 멤버들은 클래스의 public 인터페이스의 일부를 형성합니다 (public 인터페이스의 다른 부분들은 ADL 를 통해 발견되는 비멤버 함수들입니다).

클래스의 public 멤버는 어디에서나 접근 가능합니다:

class S
{
public:
    // n, E, A, B, C, U, f는 public 멤버입니다
    int n;
    enum E {A, B, C};
    struct U {};
    static void f() {}
};
int main()
{
    S::f();     // S::f는 main에서 접근 가능합니다
    S s;
    s.n = S::B; // S::n과 S::B는 main에서 접근 가능합니다
    S::U x;     // S::U는 main에서 접근 가능합니다
}

보호된 멤버 접근

protected 멤버는 파생 클래스에 대한 클래스의 인터페이스를 형성합니다(이는 클래스의 public 인터페이스와 구별됩니다).

클래스의 protected 멤버는 다음의 경우에만 접근 가능합니다

1) 해당 클래스의 멤버와 프렌드에게;
2) 해당 클래스의 파생 클래스 멤버 및 친구에게만, 보호된 멤버에 접근하는 객체의 클래스가 해당 파생 클래스이거나 해당 파생 클래스의 파생 클래스인 경우에 한함:
struct Base
{
protected:
    int i;
private:
    void g(Base& b, struct Derived& d);
};
struct Derived : Base
{
    friend void h(Base& b, Derived& d);
    void f(Base& b, Derived& d) // 파생 클래스의 멤버 함수
    {
        ++d.i;                  // OK: d의 타입은 Derived
        ++i;                    // OK: 암시적 '*this'의 타입은 Derived
//      ++b.i;                  // 오류: Base를 통해 protected 멤버에 접근할 수 없음
                                // (그렇지 않으면 다른 파생 클래스들, 예를 들어 가상의
                                // Derived2 같은 것의 기본 구현을 변경할 수 있게 됨)
    }
};
void Base::g(Base& b, Derived& d) // Base의 멤버 함수
{
    ++i;                          // OK
    ++b.i;                        // OK
    ++d.i;                        // OK
}
void h(Base& b, Derived& d) // Derived의 friend
{
    ++d.i;                  // OK: Derived의 friend는 Derived 객체를 통해
                            // protected 멤버에 접근할 수 있음
//  ++b.i;                  // 오류: Derived의 friend는 Base의 friend가 아님
}
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; // 정상
    }
};

프라이빗 멤버 접근

private 멤버는 클래스의 구현을 구성하며, 동시에 해당 클래스의 다른 멤버들을 위한 private 인터페이스를 형성합니다.

클래스의 private 멤버는 동일 인스턴스에 있든 다른 인스턴스에 있든 관계없이 해당 클래스의 멤버와 friend에게만 접근 가능합니다:

class S
{
private:
    int n; // S::n은 private입니다
public:
    S() : n(10) {}                    // this->n은 S::S에서 접근 가능합니다
    S(const S& other) : n(other.n) {} // other.n은 S::S에서 접근 가능합니다
};

명시적 캐스트 (C-스타일 및 함수-스타일)는 파생 클래스의 lvalue에서 해당 private 기반 클래스에 대한 참조로의 캐스팅, 또는 파생 클래스에 대한 포인터에서 해당 private 기반 클래스에 대한 포인터로의 캐스팅을 허용합니다.

상속

파생 클래스 에서 public, protected, private 상속의 의미를 확인하세요.

키워드

public , protected , private

결함 보고서

다음 동작 변경 결함 보고서는 이전에 게시된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 1873 C++98 protected 멤버가 파생 클래스의 friend에게 접근 가능했음 접근 불가능하게 변경됨