Спецификаторы доступа в C++
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 34 из 104.
C++ предоставляет три спецификатора access, которые определяют, кто может получить доступ к членам class: public, protected и private. Они составляют основу инкапсуляции.
class Account {
public:
std::string ownerName; // Доступен из любого места
protected:
double interestRate; // Доступен в этом классе и производных классах
private:
double balance; // Доступен только внутри этого класса
};Public members могут быть доступны из anywhere — inside the class, из derived classes и из внешнего кода. Private members являются наиболее ограниченными: accessible только внутри самого class. Protected находится между ними — для внешнего мира он действует как private, но derived classes могут получать доступ к этим members.
class Account {
private:
double balance;
public:
Account() : balance(0) {}
void deposit(double amount) {
balance += amount; // OK - внутри класса
}
};
int main() {
Account acc;
acc.deposit(100); // OK - deposit является public
// acc.balance = 500; // ERROR - balance является private
}По умолчанию все members в классе являются private, если спецификатор не указан. Это побуждает вас явно решать, что следует сделать доступным. Обычно data members делают private и предоставляют public методы для безопасного взаимодействия с ними.
Задание
ЛегкоДавайте создадим простую систему управления сотрудниками, демонстрирующую, как спецификаторы доступа определяют, кто и к чему может получить доступ. Вы создадите class, в котором одни данные полностью закрыты, некоторые доступны потенциальным производным классам, а некоторые открыты для всех.
Для организации кода вы создадите два файла:
Employee.h: определитеEmployeeclass, использующий все три спецификатора доступа для надлежащей защиты данных:- Открытый: имя employee (
string). К нему можно получить доступ anywhere - Защищённый: employee
department(string): доступен внутриclassи производнымclass, но не снаружи - Закрытый: зарплата employee (
double): доступна только внутри самогоclass - Конструктор, принимающий имя, department и зарплату для инициализации всех трёх members
- Открытый
methodgetSalary(), возвращающий значение закрытой зарплаты - Открытый
methodgetDepartment(), возвращающий значение защищённого department - Открытый
methodgiveRaise(double amount), увеличивающий зарплату на указанную сумму (только если amount положителен) - Открытый
methoddisplayInfo(), выводящий information employee в формате:"Name: <name>, Department: <department>, Salary: $<salary>"
- Открытый: имя employee (
main.cpp: продемонстрируйте работу спецификаторов доступа, взаимодействуя с объектомEmployee. Считайте имя employee, department и зарплату из input (три отдельные строки), затем:- Создайте
Employeeс введёнными значениями - Выведите имя employee напрямую, получив доступ к открытому member:
"Direct access - Name: <name>" - Выведите department с помощью getter:
"Via getter - Department: <department>" - Выведите зарплату с помощью getter:
"Via getter - Salary: $<salary>" - Дайте employee повышение на
5000.0 - Выведите
"After raise:" - Вызовите
displayInfo(), чтобы показать обновлённую information
- Создайте
Форматируйте все значения зарплаты с двумя десятичными знаками, используя std::fixed и std::setprecision(2) из <iomanip>. Преобразуйте input зарплаты из строки в double с помощью std::stod().
Главная идея заключается в том, что, хотя из main можно напрямую получить доступ к name, напрямую получить доступ к department или зарплате нельзя. Необходимо использовать открытые getter methods. Это инкапсуляция в действии: class контролирует способы доступа к своим данным и их изменения.
Попробуйте сами
#include <iostream>
#include <string>
#include <iomanip>
#include "Employee.h"
using namespace std;
int main() {
// Считать ввод
string name;
string department;
string salaryStr;
getline(cin, name);
getline(cin, department);
getline(cin, salaryStr);
double salary = stod(salaryStr);
// Установить точность для вывода зарплаты
cout << fixed << setprecision(2);
// TODO: Создать объект Employee с входными значениями
// TODO: Вывести имя сотрудника, обращаясь напрямую к публичному члену
// Format: "Direct access - Name: <name>"
// TODO: Вывести отдел с помощью метода-геттера
// Format: "Via getter - Department: <department>"
// TODO: Вывести зарплату с помощью метода-геттера
// Format: "Via getter - Salary: $<salary>"
// TODO: Дать сотруднику повышение на 5000.0
// TODO: Вывести "After raise:"
// TODO: Вызвать displayInfo() для отображения обновлённой информации
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнерПотренируйтесь самостоятельно: Онлайн-компилятор C++