Namespaces
Variants

Access specifiers

From ko.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 접근을 가집니다.

protected 또는 private 멤버에 대해 추가적인 함수나 클래스에 접근 권한을 부여하려면, friend 선언 을 사용할 수 있습니다.

접근성은 이름의 출처에 관계없이 모든 이름에 적용되므로, 에 의해 도입된 이름 typedef 또는 using 선언 (상속 생성자 제외)이 검사되며, 그것이 가리키는 이름이 아닙니다:

class A : X
{
    class B {};   // B is private in A
public:
    typedef B BB; // BB is public
};

void f()
{
    A::B y;  // error: A::B is private
    A::BB x; // OK: A::BB is public
}

멤버 접근은 가시성에 영향을 미치지 않습니다: private 및 private으로 상속된 멤버의 이름은 보이며 오버로드 해석에 고려되고, 접근 불가능한 기본 클래스로의 암시적 변환도 여전히 고려됩니다, 등. 멤버 접근 검사는 주어진 언어 구문이 해석된 후의 마지막 단계입니다. 이 규칙의 의도는 임의의 private 을(를) public 로 대체해도 프로그램의 동작을 절대 변경하지 않는다는 것입니다.

에서 사용된 이름에 대한 접근 검사는 기본 함수 인자 및 기본 템플릿 매개변수 은 선언 지점에서 수행되며, 사용 지점에서 수행되지 않습니다.

의 이름에 대한 접근 규칙은 가상 함수 은 호출 지점에서 멤버 함수가 호출되는 객체를 나타내는 표현식의 타입을 사용하여 검사됩니다. 최종 재정의자의 접근은 무시됩니다:

struct B
{
    virtual int f(); // f is public in B
};

class D : public B
{
private:
    int f(); // f is private in D
};

void f()
{
    D d;
    B& b = d;
    
    b.f(); // OK: B::f is public, D::f is invoked even though it's private
    d.f(); // error: D::f is private
}

비한정에 따라 private인 이름은 이름 검색, 한정 이름 검색을 통해 접근 가능할 수 있습니다:

class A {};

class B : private A {};

class C : public B
{
    A* p;   // error: unqualified name lookup finds A as the private base of B
    ::A* q; // OK: qualified name lookup finds the namespace-level declaration
};

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

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 is accessible to C through B
    }
};

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

멤버 접근 지정자는 클래스 레이아웃: 비정적 데이터 멤버의 주소는 선언 순서대로 증가하는 것이 보장되는 것은 멤버에 대해서만입니다 접근 지정자로 분리되지 않은C++11까지동일한 접근을 가지는C++11부터.

C++23까지

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

C++11부터

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

struct S
{
    class A;    // S::A is public
private:
    class A {}; // error: cannot change access
};

공개 멤버 접근

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에게 접근 가능했음 접근 불가능하게 변경됨