C++ Модификаторы доступа класса
В объектно-ориентированном программировании C++ (ООП) инкапсуляция данных — одна из ключевых концепций. Проще говоря, она означает "скрытие" данных и предоставление внешнему миру только необходимых интерфейсов для обеспечения безопасности данных.
Чтобы контролировать, кто может видеть эти данные, C++ предоставляет три ключевых слова, называемыемодификаторами доступа:
public(public)private(private)protected(protected)
Для простоты понимания можно представитьclass как ваш дом:
| Модификаторы | Аналогия из реального мира | Кто имеет доступ? | Типичное использование |
|---|---|---|---|
| public | Гостиная/Входная дверь | Все(внутри класса, подклассы, внешний код) | Интерфейсные функции (API), предоставляемые внешнему миру. |
| protected | Спальня | Вы и ваши дети(внутри класса, подклассы) | Данные, используемые только внутри семьи (иерархия наследования). |
| private | Сейф | Только сам класс(только внутри самого класса) | Ключевые данные, переменные, которые не следует изменять без необходимости. |
Примечание: Если модификатор не указан, члены класса C++По умолчанию
private(private).
public-члены
publicЧлены доступны в любом месте программы без чтения или записи через функции-члены, как показано в следующем примере:
Пример
Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:
Length of line : 6 Length of line : 10
закрытые члены
Закрытые члены полностью изолированы от внешней части класса; внешний код не может читать, изменять или вызывать их, а производные классы также не имеют прямых прав доступа. Только собственные функции-члены класса и сущности, получившие разрешение friend, могут работать с этим содержимым.
Если в классе не используется спецификатор доступа, члены по умолчанию являются закрытыми. Как показано в примере ниже, width автоматически попадает в закрытую область, что означает, что члены без явного указания считаются закрытыми:
Пример
На практике мы обычно определяем данные в разделе private, а связанные функции — в разделе public, чтобы эти функции можно было вызывать и вне класса, как показано ниже:
Пример
Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:
Length of box : 10 Width of box : 10
protected-члены
protectedСуществование ... в основном дляНаследование。
- Если нет наследования, то оно и
privateто же самое (не видно посторонним). - Если есть наследование,Подкласс (производный класс) может получить доступ к
protectedчлену родительского класса, но не может получить доступ кprivateчленам.
В следующей главе вы узнаете о производных классах и наследовании. Теперь вы можете увидеть в примере ниже: мы от родительского классаBoxсоздали подклассsmallBox。
Пример ниже похож на предыдущий пример; здесьwidthчлены могут быть доступны любой функции-члену производного класса smallBox.
Пример
Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:
Width of box : 5
Изменение прав доступа при наследовании
Когда вы определяете подкласс (например,class B : public A), после двоеточияpublicтакже является модификатором доступа; он определяеткак члены родительского класса "отображаются" в дочернем классе。
Это выглядит сложно, но нужно запомнить только этопринцип понижения:
Способ наследования определяет наивысший уровень доступа, который члены родительского класса имеют в дочернем классе.
Если способ наследования строже, чем исходный уровень доступа члена, уровень доступа члена "понижается" до уровня способа наследования.
Таблица изменения прав доступа
| исходные права доступа членов базового класса | public-наследование(наиболее часто используется) | protected-наследование | private-наследование |
|---|---|---|---|
| public | остаются public | понижены до protected | понижен до private |
| protected | остаются protected | остаются protected | понижен до private |
| private | Недоступно | Недоступно | Недоступно |
Примечание: «Недоступно» означает, что код дочернего класса не может напрямую использовать переменную, но переменная всё ещё существует в памяти.
исчерпывающий демонстрационный код
Для наглядности мы переименовываем переменную вpub_var(public),pro_var(protected),pri_var(private).
Пример
using namespace std;
class Parent {
public:
int pub_var;
protected:
int pro_var;
private:
int pri_var; // Доступ имеет только сам Parent
public:
Parent() { pub_var = 1; pro_var = 2; pri_var = 3; }
};
// 1. Открытое наследование — наиболее распространённое, соответствует оригиналу
class ChildA : public Parent {
public:
void test() {
cout << pub_var << endl; // ОК
cout << pro_var << endl; // ОК
// cout << pri_var << endl; // Ошибка! Приватные члены класса Parent не видны
}
};
// 2. Защищённое наследование — всё становится защищённым
class ChildB : protected Parent {
public:
void test() {
cout << pub_var << endl; // ОК, но с точки зрения ChildB он защищён
cout << pro_var << endl; // ОК
}
};
// 3. Закрытое наследование — всё становится закрытым
class ChildC : private Parent {
public:
void test() {
cout << pub_var << endl; // OK, но с точки зрения ChildC это private
cout << pro_var << endl; // OK, но с точки зрения ChildC это private
}
};
int main() {
ChildA a;
cout << a.pub_var << endl; // OK, доступен извне
// cout << a.pro_var << endl; // Ошибка, protected недоступен извне
ChildB b;
// cout << b.pub_var << endl; // Ошибка! Поскольку это protected-наследование, pub_var становится protected извне
ChildC c;
// cout << c.pub_var << endl; // Ошибка! Поскольку это private-наследование, pub_var становится private извне
return 0;
}
Итог
- Публичный: Любой может использовать его. Используется как интерфейсы (API).
- Private: Только сам класс может использовать его. Используется для хранения данных (безопасный вариант по умолчанию).
- Protected: Только семейство (цепочка наследования) может использовать его. Используется, чтобы оставить лазейку для дочерних классов.
Наследование:
- Открытое наследование: Атрибуты родительского класса остаются без изменений (наиболее часто используется).
- Закрытое/защищённое наследование: Ужесточает права доступа членов родительского класса, обычно используется в особых сценариях реализации.