Access specifiers
В member-specification класса class/struct или union определяет доступность последующих членов.
В base-specifier объявления derived class определите доступность унаследованных членов последующего базового класса.
Содержание
Синтаксис
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 } Спецификаторы доступа предоставляют автору класса возможность определять, какие члены класса доступны пользователям класса (то есть интерфейсу ), а какие члены предназначены для внутреннего использования классом ( реализацией ). ПодробноВсе объявления членов класса (включая определённые вне класса) имеют доступ ко всем именам, к которым класс имеет доступ. Локальный класс внутри функции-члена имеет доступ ко всем именам, к которым функция-член имеет доступ. Класс, определённый с ключевым словом Чтобы предоставить доступ дополнительным функциям или классам к защищённым или закрытым членам, может быть использовано объявление дружественности. Доступность применяется ко всем именам независимо от их происхождения, поэтому проверяется имя, введённое с помощью 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
}
Доступ к членам не влияет на видимость: имена закрытых и унаследованных закрыто членов видны и учитываются при разрешении перегрузки, неявные преобразования к недоступным базовым классам всё ещё учитываются и т.д. Проверка доступа к членам является последним шагом после интерпретации данной языковой конструкции. Цель этого правила состоит в том, что замена любого Проверка доступа для имён, используемых в аргументах функции по умолчанию, а также в параметрах шаблона по умолчанию, выполняется в точке объявления, а не в точке использования. Правила доступа для имён виртуальных функций проверяются в точке вызова с использованием типа выражения, используемого для обозначения объекта, для которого вызывается функция-член. Доступ окончательного переопределяющего метода игнорируется: 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
}
Имя, которое является закрытым в соответствии с неквалифицированным поиском имени, может быть доступным через квалифицированный поиск имени: 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
}
};
Любое количество спецификаторов доступа может появляться внутри класса в любом порядке.
Когда член переобъявляется в том же классе, он должен делаться с тем же доступом к члену: struct S
{
class A; // S::A is public
private:
class A {}; // error: cannot change access
};
Доступ к открытым членамПубличные члены формируют часть публичного интерфейса класса (другими частями публичного интерфейса являются нечленные функции, обнаруживаемые через 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 наследования. Ключевые словаОтчеты о дефектахСледующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||