Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 58

Бублик Володимир Васильович

Venezia
Palazzo Ducale Об'єктно-орієнтоване
програмування
Частина 1. Об'єктне програмування.

Лекція 3. Права доступу

Лекції для студентів 2 курсу


Звідки що видно?

• class Date {
• public:
• Date (unsigned int d =0, int m=0, int y=0);
• Date (const string& USdate); // “yyyy/mm/dd”
• Date (const Date&);
• ~Date();
• private:
• unsigned int _day, _month, _year;
• void fillDate
(unsigned int d, unsigned int m, unsigned int y);
• };

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 2


доступу (58)
Звідки що видно?

• class Date
• {
• public:
• //Відкрита частина видна усім
• Date (unsigned int d=0, unsigned int m=0, unsigned int y=0);
• Date (string USdate); // “yyyy/mm/dd”
• Date (const Date&);
• ~Date();
• private:
• //Закрита частина, недоступна зовні
• unsigned int _day, _month, _year;
• void fillDate (unsigned int d, unsigned int m, unsigned int y);
• };

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 3


доступу (58)
Для чого закрита частина в заголовному файлі?

• #include “Date.h”

• int main()
• {
• Date today(22,1,2007);
• // Як виділити пам’ять під today, не знаючи
• // типів кожного з атрибутів?
• cout<<today<<endl;
• return 0;
• }

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 4


доступу (58)
Звичайний перебіг

• Клас, призначений для використання атрибутом


• class Person {
• private:
• std::string _name;
• std::string _email;
• bool checkEmail();
• public:
• Person(std::string name) :_name(name) {}
• void fillEmail(std::string email);
• };

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 5


доступу (58)
Звичайний перебіг

• Для компіляції класу потрібна повна інформація про


атрибут

• #include "Person.h"
• class Card {
• private:
• Person _person;
• public:
• Card(const Person& person) :
• _person(person) {}
• };

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 6


доступу (58)
Звичайний перебіг

• Для використання класу крім його конструктора


потрібен конструктор атрибуту
• #include "Person.h"
• #include "Card.h"
• int main() {
• Person person("Who are you?");
• cout <<sizeof(person)<<endl;
• Card c(person);
• cout <<sizeof(c)<<endl;
• return 0;
• }

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 7


доступу (58)
Закриті атрибути

• Закриті атрибути класу розміщують в заголовному


файлі. Вони видимі, але, взагалі кажучи, недоступні,
всім, хто бачить заголовний файл
А на вершечку поравсь Горобець:
Усюди він, проворний молодець,
Побачив він Лисичку
І зараз обізвавсь:
— Здоровенька була, Лисичко!
Поласуй з нами, молодичко!
А виноград же то який!
У вашому гаю не виросте такий!.
без тебе знаю я…— Ні,— каже,— нам не йде,
Кислючий-прекислючий —
Оскома нападе! —
Розсердилась вона і подалась додому,
Жалкуючи, що бігла по-дурному
Л.І.Глібов

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 8


доступу (58)
Закритий vs. невидимий

• Закриті атрибути можна зробити невидимими, якщо


перейти до указників на реалізацію (ідіома pimple ―
pointer to implementation)
• // Forwarded declaration of PimplPerson
• class PimplPerson;
• class PimplCard{
• private:
• PimplPerson* _person;
• public:
• PimplCard(PimplPerson* person=nullptr)
• :_person(person) {}
• };
© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 9
доступу (58)
Компіляція і виконання

• Клас з указниками на реалізацію можна відкомпілювати


і використати без вживання жодної інформації про
агрегований атрибут

• #include "PimplCard.h"
• int main()
• {
• PimplCard pimplcard;
• cout << sizeof(pimplcard) << endl;
• return 0;
• }

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 10


доступу (58)
Схованка

• Де розмістити визначення і реалізацію класу


PimplPerson? – До файлу реалізації PimplCard.cpp
• // Prt hidden in cpp
• class PimplPerson {
• private:
• std::string _name;
• public:
• PimplPerson(std::string name):_name(name) {}
};
• // Further realisation of PimplCard
• void PimplCard::anyStuff() {}

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 11


доступу (58)
Це ваш другий паттерн

• Патерни (взірці) програмування – це архітектурні


рішення деяких частих проблем у проектуванні
програмного забезпечення

Яким був перший? Рекурентні співвідношення

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 12


доступу (58)
Для чого закривають атрибути?

Уявімо собі, що атрибути

public:
• unsigned int _day, _month, _year;

стануть відкритими.

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 13


доступу (58)
Доступні для неконтрольованого спотворення

• Date myDay(18, 2, 2006);

Якщо атрибути відкриті, то зміну їх значень користувачем,


яка може привести до некоректності, важко
контролювати

• myDay._day = 32;
• myDay._month = 13;
• myDay._year = 3333;

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 14


доступу (58)
Доступ за допомогою модифікатора

Модифікатор локалізує місця можливих змін значень


атрибутів та контролює їх коректність

• void Date::setDay (unsigned int day)


• {
• fillDate(day, Month(_month), _year);
• return;
• }

• якщо атрибут некоректний, функція fillDate створить


аварійну ситуацію,

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 15


доступу (58)
Для чого закривають методи?

• Закривають службові методи, не призначені для


вживання за межами класу
• void Date::fillDate(int d, Month m, int y) {
• if(!defaultSet) {
• defaultSet=true;
• setDefault();
• #ifndef _NDEBUG
• cout<<"Date set toDefault:"<<*this<<endl;
• #endif
• return;
• } . . . . . .

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 16


доступу (58)
Приклади використання закритого методу

• Різні види конструкторів забезпечують інтерфейс до


одного і того ж методу
• Date::Date (unsigned int d, Month m, unsigned int y)
• {
• fillDate(d, m, y);
• }
• Date::Date (unsigned int d,
unsigned int m, unsigned int y)
• {
• fillDate(d, Month(m), y);
• }

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 17


доступу (58)
Делегування конструктора С++11

• Різні види конструкторів забезпечують інтерфейс до


одного і того ж методу
• Date::Date (unsigned int d, Month m, unsigned int y)
• {
• fillDate(d, m, y);
• }
• Date::Date (unsigned int d,
unsigned int m, unsigned int y)
• :Date(d, Month(m), y)
• {}

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 18


доступу (58)
Атрибути об'єкту

Атрибути об'єкту, як і методи


• _day, _month, _year
позбавлені сенсу поза об'єктом

Метод, наприклад,
• fillDate; setDay(5); month();
не можна викликати без об'єкту.
Метод завжди знає свій об'єкт, до якого його
застосовано. Він звертається до свого об'єкту неявно
(_day, _month, _year ) або через указник
this (this->_day, this->fillDate(d, m, y); )

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 19


доступу (58)
Статичні атрибути і методи

• Статичний атрибут не належить жодному об'єкту


• Статичний метод не застосовується до жодного
окремого об'єкту (він не знає this)
• class Date
• {
• public:
• static void setDefault (); //за таймером
• private:
• static Date defaultDate;
• static bool defaultSet;. . . . . . . . . . . .
• };

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 20


доступу (58)
Створення статичних об'єктів

• // Компонувальник створить дату за замовчуванням,


• // виконавши відповідний конструктор
• // до початку виконання основної програми,
• // Скорочений запис:
• Date Date::defaultDate;
• // Повний запис:
• Date Date::defaultDate = Date();

• // Зафіксується факт створення замовчування


• bool Date::defaultSet = false;

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 21


доступу (58)
Часова діаграма

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 22


доступу (58)
#include <ctime>

• void Date::setDefault ()
• {
• struct tm * today =new tm;
• time_t timer;

• time( &timer );
• today = gmtime(&timer);

• defaultDate._day = today->tm_mday;
• defaultDate._month = ++(today->tm_mon);
• defaultDate._year = today->tm_year+=1900;
• }

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 23


доступу (58)
Обробка параметрів у конструкторі

Відсутні параметри дати тепер беруться з defaultDate

• _day = d? d: defaultDate._day;
• _month=m? m: defaultDate._month;
• _year= y? y: defaultDate._year;

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 24


доступу (58)
Статичні методи vs. утиліти класу

• Статичний метод, наприклад, Point::amount має доступ


до закритої частини класу і викликається поза класом
через оператор розв'язання області дії
• Point :: amount();

• Утиліта класу, наприклад,


ostream& operator<<(ostream&, const Point&);
не має доступу до закритої частини класу і не потребує
оператора розв'язання області дії

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 25


доступу (58)
Надання виняткових прав

• Закриті атрибути доступні для використання лише


членам класу, а також функціям або класам, яким
надані для цього спеціальні повноваження (friends)

Amicus Plato, sed magis amica veritas

Платон мені друг, але істина дорожча

Платон і Арістотель
© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 26
доступу (58)
Порушення прав доступу

• Виняткові права доступу до атрибутів


• Виняткові права доступу до закритих методів
• Виняткові права на створення і видалення об'єктів

Виняткові права можна надати


• Іншому класу
• Окремому методу іншого класу
• Утиліті класу

Для надання виняткових прав потрібні серйозні підстави

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 27


доступу (58)
Приклад. Офіс

ant

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 28


доступу (58)
Винятки

• Тільки працедавець Employer має право створити


робоче місце Employee і призначити особу Person на
певну посаду Position

• Тільки бухгалтеру Accountant, а точніше його методу


нарахування зарплати payroll() працедавець Employer
надає доступ до свого штатного розпису

• Тільки бухгалтеру Accountant, а точніше його методу


нарахування зарплати payroll (const Employee &)
доступна інформація про заробітну плату посади, яку
займає службовець
© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 29
доступу (58)
Службовець

• class Employee
• {
• friend class Employer;
• private:
• const Person & _who;
• const Position & _what;
• Employee(const Person & who, const Position & what);
• ~Employee();
• public:
• const Person& who() const;
• const Position& what() const;
• };
© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 30
доступу (58)
Працедавець.1

• class Employer
• {
• friend void Accountant::payroll();

• private:
• Accountant * _accountant;
• unsigned int _volume;
• struct Staff; //Hidden implementation
• Staff * _office; // *** pimpl

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 31


доступу (58)
Працедавець.2

• public:
• Employer(unsigned int volume);
• ~Employer();
• void hire
• (const Person &, const Position &);
• void fire(unsigned int);
• void pay();
• };

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 32


доступу (58)
Посада.1

• class Position
• {
• friend void Accountant::payroll(const Employee&);
• private:
• const unsigned int _len;
• string _name;
• unsigned int _salary;
• unsigned int getSalary() const;

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 33


доступу (58)
Посада.2

• public:
• string getPositionName() const;
• Position(unsigned int, char [], unsigned int);
• ~Position();
• };

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 34


доступу (58)
Особа

• class Person
• {
• private:
• const unsigned int _len;
• string _name;
• public:
• string getName() const;
• Person(unsigned int, char []);
• ~Person();
• };

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 35


доступу (58)
Бухгалтер

• class Accountant
• {
• private:
• void payroll (const Employee &);
• const Employer & _myEmployer;

• public:
• Accountant (Employer & employer):
_myEmployer(employer){};
• ~Accountant ()
• void payroll();
• };

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 36


доступу (58)
Надання дружніх прав

• Регламентується виключно постановкою задачі і


вимогами замовника, а не технічною некомпетентністю
розробника програми

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 37


доступу (58)
Так не робіть!

• class Point
• {
• friend Point operator+(const Point&, const Point&);
• double _x;
• double _y;
• public:
• Point (double x=0, double y=0);
• Point (const Point &);
• ~Point();
• };

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 38


доступу (58)
Тільки так!

• class Point
• {
• friend Point operator+(const Point&, const Point&);
• double _x;
• double _y;
• public:
• Point (double x=0, double y=0);
• Point (const Point &);
• ~Point();
• };
• const Point operator+(const Point&, const Point&);
© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 39
доступу (58)
Можливість вибору: метод vs утиліта

• Що включати до класу його членом (методом), що


приєднувати утилітою для його обслуговування?
• if (f is operator>> or operator<<) {
•    make f a non-member function;
• if (f needs access to non-public members of Class)
•       make f a friend of Class (exceptionally - BB);
• }
• else if (f can be implemented via Class's
•          public interface)
•    make f a non-member function;
• else
•    make f a member function of Class;
• //Scott Meyers, How Non-Member Functions Improve Encapsulation (фрагмент)

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 40


доступу (58)
Де розмістити функцію?

• Перша крайність

• Всі функції члени класу

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 41


доступу (58)
Функція-член класу (метод)
• Date& Date::operator+=(unsigned int dn) {
• _day+=dn; // тут і скрізь далі this->_day
• do {
• unsigned int max;
• switch (_month)
• {
• case 2:
• max=28+leapYear(_year); break;
• case 4: case 6: case 9: case 11:
• max=30; break;
• case 1: case 3: case 5: case 7: case 8: case 10: case 12:
• max=31; break;
• default:
• max=0; throw max;
• }

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 42


доступу (58)
Функція-член класу (метод)
• if(_day<=max)
• break;
• _day-=max;
• _month++;
• if(_month>12)
• {
• _month-=12;
• _year++;
• }
• }
• while(true);
• return *this;
• }
• // Одержує повні права доступу до усіх частин об'єкту,
• // але й несе повну відповідальність за їх коректне використання
• // Слабкий контроль за доступом до атрибутів (режим повної довіри)

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 43


доступу (58)
Друга крайність

• Всі утиліти класу дружні функції

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 44


доступу (58)
Виняткові права

• class Date {
• friend Date& operator+=(Date& date, unsigned int dn);
• public:
• Date(unsigned int d =0,unsigned int m=0,
unsigned int y=0);
• Date (const string& USdate); // “yyyy/mm/dd”
• Date (const Date&);
• ~Date();
• private:
• unsigned int _day, _month, _year;
• void fillDate(unsigned int d,unsigned int m,
unsigned int y);
• };

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 45


доступу (58)
Надмірна довіра (Off top)

• І ти, Брут!

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 46


доступу (58)
Дружня функція-утиліта класу
• Date& operator+=(Date& date, unsigned int dn) {
• date._day+=dn;
• do {
• unsigned int max;
• switch (date._month)
• {
• case 2:
• max=28+ Date::leapYear(date._year); break;
• case 4: case 6: case 9: case 11:
• max=30; break;
• case 1: case 3: case 5: case 7: case 8: case 10: case 12:
• max=31; break;
• default:
• max=0; throw max;
• }

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 47


доступу (58)
Дружня функція-утиліта класу
• if(date._day<=max)
• break;
• date._day-=max;
• date._month++;
• if(date._month>12)
• {
• date._month-=12;
• date._year++;
• }
• }
• while(true);
• return date;
• }
• // Також одержує повні права доступу до усіх частин об'єкту,
• // але не несе відповідальності за їх коректне використання
• // Слабкий контроль за доступом до атрибутів (режим повної довіри)

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 48


доступу (58)
Порушення інкапсуляції

Неконтрольований доступ до закритої частини класу


називатимемо порушенням його інкапсуляції.

Її рівною мірою порушують як члени класу («рідні діти»),


так і дружні утиліти («прийомні діти»).

Завжди потрібне належне обґрунтування. Ще краще


обмежувати доступ до закритої частини як членам
класу, так і утилітам, позбавляючи останніх статусу
дружніх.

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 49


доступу (58)
Функція-член класу (метод)
• Date& Date::operator+=(unsigned int dn) {
• setDay(getDay()+dn); // тут і скрізь далі this->setDay()
• do {
• unsigned int max;
• switch (getMonth())
• {
• case 2:
• max=28+leapYear(getYear()); break;
• case 4: case 6: case 9: case 11:
• max=30; break;
• case 1: case 3: case 5: case 7: case 8: case 10: case 12:
• max=31; break;
• default:
• max=0; throw max;
• }

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 50


доступу (58)
Функція-член класу (метод)
• if(getDay()<=max)
• break;
• setDay(getDay()-max);
• setMonth(getMonth()+1);
• if(getMonth()>12)
• {
• setMonth(getMonth()-12);
• setYear(getYear()+1);
• }
• }
• while(true);
• return *this;
• }
• // Звертається до атрибутів за допомогою селекторів і модифікаторів,
• // не користуючись своїми винятковими правами.
• // Повний контроль за доступом до атрибутів

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 51


доступу (58)
Дружня функція-утиліта класу
• Date& operator+=(Date& date, unsigned int dn) {
• date.setDay(date.getDay()+dn);
• do {
• unsigned int max;
• switch (date.getMonth())
• {
• case 2:
• max=28+Date::leapYear(date.getYear()); break;
• case 4: case 6: case 9: case 11:
• max=30; break;
• case 1: case 3: case 5: case 7: case 8: case 10: case 12:
• max=31; break;
• default:
• max=0; throw max;
• }

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 52


доступу (58)
Дружня функція-утиліта класу
• if(date.getDay()<=max)
• break;
• date.setDay(date.getDay()-max);
• date.setMonth(date.getMonth()+1);
• if(date.getMonth()>12)
• {
• date.setMonth(date.getMonth()-12);
• date.setYear(date.getYear()+1);
• }
• }
• while(true);
• return date;
• }
• // Звертається до атрибутів за допомогою селекторів і модифікаторів,
• // не вимагаючи собі виняткових прав.
• // Повний контроль за доступом до атрибутів

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 53


доступу (58)
Вміст заголовного файлу

• Визначення класу (класів)

• Сигнатури утиліт класу (з їх визначеннями в разі inline)

• В С++20 зявилося поняття модуля, який приєднується


не препроцесором, а новою командою import

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 54


доступу (58)
Інтерфейс модуля

• // Файл math.cppm

• export module math;

• namespace math
• {

• export bool is_prime(long i);


• }

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 55


доступу (58)
Реалізація модуля

• // Файл math.cpp
• #include <cmath>
• using namespace std;
• module math;
• namespace math {
• long max_check(long i) { return std::sqrt(i)
+1; }
• bool is_prime(long i){
• if (i == 1) return false;
• if (i % 2 == 0) return i == 2;
• for (long j = 3; j < max_check(i); j += 2)
• if (i % j == 0) return false;
• return true;}
• } // namespace math
© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 56
доступу (58)
Використання модуля

• // Файл main.cpp
• #include <iostream>
• using namespace std;
• import math;

• int main(){
• using namespace math;
• cout << "982'451'653 is " <<
• (is_prime(982'451'653) ? "" : "not ") <<
• "a prime number.\n";
• // max_check not exported
• return 0;
• }

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 57


доступу (58)
Висновки

Для порушення прав доступу повинні бути серйозні


підстави, що випливають з умови задачі

Статус утиліти класу, наприклад, ще не дає виняткових


прав

Як можна скорочуйте кількість функцій, що мають доступ


до закритої частини класу, віддаючи перевагу
селекторам та модифікаторам

© 2006-2021 Бублик В.В. ООП-1. Об'єктне програмування. Права 58


доступу (58)

You might also like