Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект лекцій по С.doc
Скачиваний:
7
Добавлен:
16.11.2019
Размер:
393.73 Кб
Скачать

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 необхідно також доповнити реалізації методів. Зробіть

це самостійно.