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

В member-specification класса class/struct или union определяет доступность последующих членов.

В base-specifier объявления derived class определите доступность унаследованных членов последующего базового класса.

Содержание

Синтаксис

public : объявления-членов (1)
protected : объявления-членов (2)
private : объявления-членов (3)
public базовый-класс (4)
protected базовый-класс (5)
private базовый-класс (6)
1) Члены, объявленные после спецификатора доступа, имеют публичный доступ к членам.
2) Члены, объявленные после спецификатора доступа, имеют защищённый доступ к членам.
3) Члены, объявленные после спецификатора доступа, имеют доступ private членов.
4) Public inheritance : публичные и защищённые члены базового класса , перечисленные после спецификатора доступа, сохраняют свой уровень доступа в производном классе.
5) Protected inheritance : открытые и защищённые члены базового класса , перечисленные после спецификатора доступа, становятся защищёнными членами производного класса.
6) Приватное наследование : публичные и защищённые члены базового класса , указанные после спецификатора доступа, являются приватными членами производного класса.

Закрытые члены базового класса всегда недоступны для производного класса независимо от типа наследования: 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
}

Спецификаторы доступа предоставляют автору класса возможность определять, какие члены класса доступны пользователям класса (то есть интерфейсу ), а какие члены предназначены для внутреннего использования классом ( реализацией ).

Подробно

Все члены класса (тела member functions , инициализаторы объектов-членов и полные определения nested class definitions ) имеют доступ ко всем именам, доступным классу. Локальный класс внутри функции-члена имеет доступ ко всем именам, доступным этой функции-члену.

Класс, определённый с ключевым словом class , имеет приватный доступ для своих членов и базовых классов по умолчанию. Класс, определённый с ключевым словом struct , имеет публичный доступ для своих членов и базовых классов по умолчанию. Объединение имеет публичный доступ для своих членов по умолчанию.

Чтобы предоставить доступ к дополнительным функциям или классам к защищённым или приватным членам, может использоваться объявление дружбы .

Доступность применяется ко всем именам без учета их происхождения, поэтому проверяется имя, введенное с помощью typedef или using declarations (за исключением наследуемых конструкторов), а не имя, на которое оно ссылается:

class A : X
{
    class B {};   // B является приватным в A
public:
    typedef B BB; // BB является публичным
};
void f()
{
    A::B y;  // ошибка: A::B является приватным
    A::BB x; // OK: A::BB является публичным
}

Доступ к членам не влияет на видимость: имена приватных и унаследованных приватно членов видны и учитываются при разрешении перегрузки, неявные преобразования в недоступные базовые классы всё равно рассматриваются и т.д. Проверка доступа к членам является последним шагом после интерпретации любой данной языковой конструкции. Цель этого правила заключается в том, чтобы замена любого private на public никогда не изменяла поведение программы.

Проверка доступа для имён, используемых в аргументах по умолчанию функций , а также в стандартных параметрах шаблонов , выполняется в точке объявления, а не в точке использования.

Правила доступа для имён виртуальных функций проверяются в точке вызова с использованием типа выражения, которое обозначает объект, для которого вызывается функция-член. Доступ к финальному переопределению игнорируется:

struct B
{
    virtual int f(); // f является public в B
};
class D : public B
{
private:
    int f(); // f является private в D
};
void f()
{
    D d;
    B& b = d;
    b.f(); // OK: B::f является public, вызывается D::f несмотря на private доступ
    d.f(); // ошибка: D::f является private
}

Имя, которое является приватным согласно name lookup без квалификации, может быть доступно через квалифицированный поиск имени:

class A {};
class B : private A {};
class C : public B
{
    A* p;   // ошибка: поиск неквалифицированного имени находит A как приватный базовый класс B
    ::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 доступен для C через B
    }
};

Любое количество спецификаторов доступа может присутствовать внутри класса в любом порядке.

Спецификаторы доступа членов могут влиять на расположение класса : адреса нестатических членов-данных гарантированно увеличиваются в порядке объявления только для членов не разделённых спецификатором доступа (до C++11) с одинаковым доступом (начиная с C++11) .

(до C++23)

Для стандартных типов размещения все нестатические члены данных должны иметь одинаковый уровень доступа.

(начиная с C++11)

Когда член переобъявляется в пределах одного и того же класса, это должно происходить с тем же уровнем доступа:

struct S
{
    class A;    // S::A является публичным
private:
    class A {}; // ошибка: нельзя изменить уровень доступа
};

Доступ к открытым членам

Публичные члены формируют часть публичного интерфейса класса (другими частями публичного интерфейса являются нечленные функции, обнаруживаемые через ADL ).

Открытый член класса доступен везде:

class S
{
public:
    // n, E, A, B, C, U, f являются публичными членами
    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
}

Доступ к защищённым членам

Защищённые члены формируют интерфейс класса для его производных классов (что отличается от публичного интерфейса класса).

Защищенный член класса доступен только

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 (иначе можно было бы изменять
                                // другие производные классы, например гипотетический
                                // Derived2, базовую реализацию)
    }
};
void Base::g(Base& b, Derived& d) // функция-член Base
{
    ++i;                          // OK
    ++b.i;                        // OK
    ++d.i;                        // OK
}
void h(Base& b, Derived& d) // Друг Derived
{
    ++d.i;                  // OK: друг Derived может получить доступ к защищённому
                            // члену через объект типа Derived
//  ++b.i;                  // ошибка: друг Derived не является другом Base
}
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-стиль и функциональный стиль) позволяет выполнять приведение от производного lvalue к ссылке на его закрытый базовый класс, или от указателя на производный класс к указателю на его закрытый базовый класс.

Наследование

См. производные классы для понимания значения public, protected и private наследования.

Ключевые слова

public , protected , private

Отчеты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
CWG 1873 C++98 protected members were accessible to friends of derived classes made inaccessible