- •1 Парадигми та мови програмування
- •1.1 Процедурне програмування
- •1.2 Об'єктне (модульне) програмування
- •1.3 Об'єктно-орієнтовне програмування
- •2 Програмне середовище
- •3 Базові поняття програмування
- •4 Процедурно-орієнтоване програмування
- •4.1 Функції
- •4.2 Вбудовані (inline) функції
- •4.3 Передача параметрів
- •4.4 Обчислення значення функцій
- •4.4. Обчислення значення функції — вихід із функції; особливості повернення та використання іменованого значення, іменованої константи
- •4.5 Рекурсія
- •4.5. Рекурсія
- •4.6 Довизначення (overloading) функцій
- •4.6. Довизначення (overloading) функцій
- •4.7 Узагальнені функції (function template)
- •4.8 Непряме використання функцій: указники на функції, їх тип, ініціалізація і присвоєння
- •4.9 Видимість
- •4.10 Тривалість життя об’єктів
- •5 Об'єктне програмування
- •5.1 Класи і об'єкти, члени класів
- •5.2 Інтерфейс класу, реалізація класу; визначення і оголошення класу
- •5.3 Створення і ініціалізація об'єктів, довизначення конструкторів, замовчуваний конструктор, копіювання, поверхневе і глибоке копіювання, ініціалізація і присвоєння, копіювальний конструктор
- •5.4 Cтатичні члени класів і статичні класні функції
- •5.5 Константні об'єкти, константні функції, змінювані члени константних об'єктів (mutable)
- •5.6 Поточний об'єкт this, указники на члени класу і класні функції, порівняння з указниками на (позакласні) функції, указники на статичні члени класу
5.5 Константні об'єкти, константні функції, змінювані члени константних об'єктів (mutable)
Константні об'єкти, константні функції, змінювані члени константних об'єктів (mutable)
Як і будь-які інші об'єкти, екземпляри класів можуть бути сталими. Застосування
методів до сталих об'єктів має певні обмеження: методи не мають права змінювати
ці сталі об'єкти. Так з'являється поняття константної класної функції як функції,
що не має права змінювати об'єкт, який її активізує. Якщо ми спробуємо відкомпілювати
код
const Date myDate = Date();
myDate.showDate();
то одержимо повідомлення про помилку, викликану спробою застосування неконстантної
функції до сталого об'єкту. При виклику функції компілятор обмежується формальною
перевіркою наявності у неї кваліфікатора const . Компілятор не додасть цього
кваліфікатора сам, але разом з тим, якщо вже функція позначена константною,
то він не дозволить їй модифікацію свого об'єкта.
void Date::showDate() const
{
cout<<_day<<':'<<_month<<':'<<_year<<endl;
}
Константну функцію може активізувати і неконстантний об'єкт, але не навпаки.
Доповнимо інтерфейс іншими константними функціями
class Date
{
static Date defaultDate;
int _day, _month, _year;
public:
Date (int d=0, int m=0, int y=0);
Date (const char *cdate);
Date (const Date&);
// Константні методи
void showDate() const;
int day() const;
int month() const;
int year() const;
// Статичні методи
static void setDefault(int,int,int);
static void setDefault();
static void showDefault();
}
Звернемо увагу на те, що кваліфікатор const стає частиною сигнатури функції.
Ось невеликий приклад. В класі Point одночасно існують дві пари функцій. сигнатури
яких розрізняються лише кваліфікатором const . Константна функція координати
x() або y() повертає значення відповідної координати, в той час як неконстантна
функція повертає лівостороннє значення. Тому її можна вживати як зліва, так
і справа від знаку присвоєння.
class Point
{
// Атрибути
private:
double _x;
double _y;
// Методи
public:
double& x();
double x() const;
double& y();
double y() const;
Point (double a=0, double b=0);
Point operator+(Point);
bool operator==(Point);
double modulus ();
double phi ();
}
Відповідні реалізації
double& Point::x()
{
cout<<"non-const ";
return _x;
};
double Point::x() const
{
cout<<"const ";
return _x;
};
double& Point::y()
{
cout<<"non-const ";
return _y;
};
double Point::y() const
{
cout<<"const ";
return _y;
};
і виклики
int main()
{
Point a(1,2);
cout<<a.x()<<' '<<a.y(); //не сталі
a.x()=10; a.y()=20; //не сталі
const Point c(3,4);
cout<<c.x()<<' '<<c.y(); //сталі
return 0;
}
Розглянемо ще один простий приклад
class Screen
{
public:
Screen(int, int, char*);
Screen(const Screen&);
~Screen();
void home();
void move(int, int);
void move();
char get() const;
void set(char);
void show();
void clear();
private:
static const int maxHeight;
static const int maxWidth;
int _height;
int _width;
char *_wContent;
int _cursor;
char _filler;
};
Клас призначено для виведення на екран текстових вікон. Ось визначення констант
і реалізація його методів
const int Screen::maxHeight=24;
const int Screen::maxWidth=80;
Screen::Screen(int m, int n, char* s)
{
_filler = ’.’;
_width = m>maxWidth? maxWidth: m;
_height = n>maxHeight? maxHeight: n;
int len = strlen(s)>_height*_width?
height*_width: strlen(s);
_wContent = new char [_height*_width+1];
_wContent[_height*_width]='\0';
for(int k=0;k<len;k++) *(_wContent+k) = *s++;
for(;k<_height*_width;k++) *(_wContent+k) = ' ';
_cursor = 0;
};
Screen::Screen(const Screen& v)
{
_filler = v._filler;
_height = v._height;
_width = v._width;
_wContent = new char [_height*_width+1];
strcpy(_wContent,v._wContent);
_cursor=v._cursor;
}
Screen::~Screen()
{
delete []_wContent;
}
void Screen::home()
{
_cursor=0;
};
void Screen::move(int i, int j)
{
if ((i>=_height) || (j>=_width))
_cursor=0;
else
_cursor = _width*i + j;
};
void Screen::move()
{
if ((++_cursor)>=_width*_height) _cursor=0;
};
char Screen::get() const
{
return *(_wContent + _cursor);
};
void Screen::set(char a)
{
*(_wContent + _cursor)=a;
}
void Screen::clear()
{
for (int i=0; i<_height*_width; i++)
*(_wContent+i)= _filler;
_cursor=0;
}
void Screen::show()
{
home();
for(int i=0;i<_height;i++)
{
for (int j=0; j<_width; j++)
{
cout<<get();
move();
}
cout<<endl;
}
cout<<_cursor<<endl;
};
Тепер розглянемо визначення
const Screen w(4,3,"aaaabbbbcccc");
спробуємо застосувати до w метод show . З цього нічого не вийде, оскільки
метод show не константний. Стати константним йому заважають два методи home
і move , які змінюють значення курсору.
Введемо до поняття сталого об'єкту одне послаблення. Скажемо, що в ньому можна
виділити другорядні атрибути, значення яких не впливають на значення об'єкту
з точки зору його предметної семантики. Вважатимемо, наприклад, що до таких
відноситься позиція курсору. Курсор не впливає на вміст вікна, а служить лише
для посимвольної його обробки. Позначимо через mutable атрибути, які дозволяється
змінювати константним функціям. Тоді всі три згадані функції можна буде вважати
константними.
class Screen
{
public:
Screen(int, int, char*);
Screen(const Screen&);
~Screen();
void home() const;
void move(int, int) const;
void move() const;
char get() const;
void set(char);
void show() const;
void clear();
private:
static const int maxHeight;
static const int maxWidth;
int _height;
int _width;
char *_wContent;
mutable int _cursor;
char _filler;
};
Кваліфікаторами const необхідно також доповнити реалізації методів. Зробіть
це самостійно.