C++. Функції класу, що оголошені з константним (const) покажчиком this та непостійним (volatile) покажчиком this

Функції класу, що оголошені з константним (const) покажчиком this та непостійним (volatile) покажчиком this


Зміст



1. Як виглядає загальна форма оголошення функції з константним покажчиком this?

Оголошення функції у класі (на прикладі функцій MyFun1(), MyFun2()) з константним покажчиком this має такий загальний вигляд:

class CMyClass
{
    private:
    // приховані члени даних та методи класу
    // ...

    public:
    // функція оголошена з константним покажчиком this
    return_type MyFun1(parameters) const; // out-of-line
    return_type MyFun2(parameters) const // inline реалізація
    {
        // тіло функції
        // ...
    }
}

// реалізація out-of-line функції
return_type CMyClass::MyFun1(parameters) const
{
    // тіло функції MyFun1()
    // ...
}

де

  • return_type – тип, що повертається тією чи іншою функцією;
  • parameters – параметри, які отримує функція.

У вищенаведеному фрагменті, у класі CMyClass оголошуються дві функції з константним покажчиком this. Функція MyFun1() реалізована за межами класу (типу out-of-line). Функція MyFun2() реалізована в класі (типу inline). Перед тілом кожної функції стоїть ключове слово const.

2. В чому полягає суть оголошення функції з константним покажчиком this?

У функції з константним покажчиком this перед тілом функції ставиться ключове слово const. Це означає, що тіло функції має обмежені можливості використання.

Слід зауважити, що у цьому випадку ключове слово const не має відношення до значення, що повертається функцією. Воно має значення тільки для покажчика this, що використовується у функції.

Якщо функція оголошена з константним покажчиком this, то в тілі функції заборонено змінювати дані класу. При спробі змінити дані класу, буде виникати помилка компіляції.

3. Приклад, що демонструє відмінність між функціями з константним покажчиком this та без нього

Відмінність між звичайною функцією та функцією з константним покажчиком this добре видно в реалізації нижченаведеного класу.

Нехай задано клас CRadius, що реалізує радіус деякого об’єкта чи геометричної фігури. У класі реалізовано:

  • внутрішній член даних типу double;
  • конструктор CRadius();
  • звичайну функцію GetRadius(), яка збільшує радіус удвічі і повертає його значення;
  • функцію GetRadius2(), оголошену з константним покажчиком this. Дана функція повертає значення внутрішньої змінної radius.
// клас CRadius
class CRadius
{
    double radius;

    public:
    CRadius(void); // конструктор класу за замовчуванням

    // Звичайна функція-член класу,
    // цій функції неявно передається покажчик: CRadius * const this
    double GetRadius(void)
    {
        radius *= 2.0; // дозволено
        return radius;
    }

    // Функція-член класу, оголошена з const
    // цій функції передається покажчик: const CRadius * const this
    double GetRadius2(void) const
    {
        //radius = 2.0; // Заборонено! Помилка компіляції
        return radius;
    }
};

Якщо у функції GetRadius2() спробувати змінити значення внутрішньої змінної radius, то вийде помилка компіляції:

Error: 'radius' cannot be modified because it is being accessed through a const object

Ключове слово const перед тілом функції в класі означає, що функції заборонено вносити будь-які зміни в члени даних класу.

Використання класу CRadius в деякому програмному коді, наприклад, обробнику події:

CRadius CR;

double d;
d = CR.GetRadius2(); // d = 1.0 - виклик функції з константним this
d = CR.GetRadius(); // d = 1.0 - виклик звичайної функції-члена

4. Яким чином модифікується покажчик this, що передається функції-члену, яка оголошена з константним покажчиком this?

Нехай задано клас CRadius, в якому є функція-член з константним покажчиком this:

// клас CRadius
class CRadius
{
    double radius;

    public:
    CRadius(void); // конструктор класу за замовчуванням

    // Звичайна функція-член класу,
    // цій функції неявно передається покажчик: CRadius * const this
    double GetRadius(void)
    {
        radius *= 2.0; // дозволено
        return radius;
    }

    // Функція-член класу, оголошена з const
    // цій функції передається покажчик: const CRadius * const this
    double GetRadius2(void) const
    {
        //radius = 2.0; // Заборонено! Помилка компіляції
        return radius;
    }
};

Покажчик this у класі є невидимий, функціям класу він передається неявно. Це означає, що при спробі явного опису покажчика this у класі, компілятор видасть помилку.
Звичайній функції-члену класу GetRadius() покажчик this передається в неявному вигляді як:

CRadius * const this;

Функції-члену GetRadius2() невидимий покажчик this передається з ключовим словом const:

// модифікований покажчик this
const CRadius * const this;

Запис

const CRadius

означає, що об’єкт типу CRadius є константним об’єктом. І тому, змінювати значення об’єкту у тілі функції GetRadius2() не можна. Отже, не можна змінювати значення внутрішніх членів-даних класу у функції GetRadius2(). Спроба змінити значення внутрішнього члену даних radius у тілі функції GetRadius2() викличе помилку компіляції.

5. Для чого потрібно використовувати функції класу з константним покажчиком this?

Функції з константним покажчиком this доцільно використовувати у випадках, коли потрібно, щоб функція-член базового класу випадково не перевизначилась у похідних класах. У цьому випадку константний покажчик this служить захистом даних базового класу від випадкової їх зміни у похідних класах.

6. Що буде, якщо ключове слово const розмістити перед іменем функції, а не перед тілом функції?

Це є важливо. У цьому випадку, функція повертає константне значення. Але змінювати внутрішні дані класу у тілі функції можна.
Ключове слово const перед іменем функції відноситься до значення, яке повертається функцією. Ключове слово const перед тілом функції відноситься до покажчика this.

7. Чи можна оголошувати ключове слово const для статичних функцій-членів?

Оголошення статичної функції-члена з ключовим словом const не має змісту. При виклику статичної функції-члена, невидимий покажчик this не передається цій функції. При спробі оголошення статичної функції-члена з константним покажчиком this компілятор видасть помилку

... modifiers not allowed on static members functions

8. Яка загальна форма оголошення функції-члена з непостійним покажчиком this? Ключове слово volatile

Для того, щоб оголосити функцію-член з непостійним покажчиком this використовується ключове слово volatile.
Загальна форма оголошення функції з непостійним покажчиком this в класі має приблизно наступний вигляд:

class CMyClass
{
    // приховані члени даних та методи класу
    // ...

    public:
    // загальнодоступні члени даних та методи класу
    // функція-член з непостійним покажчиком this
    return_type MyFun1(parameters) volatile; // out-of-line
    return_type MyFun2(parameters) volatile // inline
    {
        // тіло функції
        // ...
    }
}

// реалізація out-of-line функції
return_type CMyClass::MyFun1 volatile
{
    // тіло функції MyFun1()
    // ...
}

де

  • return_type – тип, що повертається тією чи іншою функцією;
  • parameters – параметри, які отримує функція.

У вищенаведеному фрагменті, у класі CMyClass оголошуються дві функції з непостійним (volatile) покажчиком this. Функція MyFun1() реалізована за межами класу (типу out-of-line). Функція MyFun2() реалізована у класі (типу inline). Перед тілом кожної функції стоїть ключове слово volatile.

9. У яких випадках доцільно оголошувати функцію з непостійним (volatile) покажчиком this?

Оголошення функції як volatile доцільно використовувати у випадках, коли потрібно обробляти об’єкт класу різними процесами, до яких можна віднести:

  • обробка об’єкту процесором;
  • обробка з допомогою фонових прикладних програм;
  • обробка з допомогою програм обробки переривань.

10. Що дає використання ключового слова volatile для функції-члена класу?

Функція-член класу, що оголошена з ключовим словом volatile трактується компілятором у різних випадках по різному. Для таких функцій компілятор відключає деякі види оптимізації в залежності від типу оголошеного об’єкту.
Функції-члени класу, що оголошені з ключовим словом volatile можна використовувати як для автоматичних об’єктів так і для непостійних (volatile) об’єктів.
Для константних об’єктів використання функцій з непостійним покажчиком заборонено. Знову ж таки, все залежить від налаштувань та реалізації компілятора.

11. Приклад використання функцій-членів класу з непостійним покажчиком this

Нехай дано клас CRadius. У класі реалізовано:

  • внутрішній член-даних radius;
  • конструктор CRadius();
  • звичайну функцію-член класу GetRadius();
  • дві фунції-члени класу з непостійним покажчиком this: GetRadius2() та SetRadius().
// клас CRadius
class CRadius
{
    double radius;

    public:
    CRadius(void); // конструктор класу за замовчуванням

    // Звичайна функція-член класу,
    // цій функції неявно передається CRadius * const this
    double GetRadius(void)
    {
        return radius;
    }

    // Функція-член класу, оголошена з volatile
    // цій функції передається volatile CRadius * const this
    double GetRadius2(void) volatile
    {
        return radius;
    }

    // Функція-член класу, оголошена з volatile
    void SetRadius(double r) volatile
    {
        radius = r;
    }
};

Використання класу в іншому програмному коді

CRadius CR1; // автоматичний об'єкт
volatile CRadius CR2; // непостійний об'єкт

double d;

// автоматичний об'єкт
CR1.SetRadius(5.5);
d = CR1.GetRadius2(); // d = 5.5

// непостійний об'єкт
CR2.SetRadius(6.7);
d = CR2.GetRadius2(); // d = 6.7

Як видно з програмного коду, функції-члени з непостійним (volatile) покажчиком this можна використовувати для автоматичних та непостійних об’єктів. У цьому випадку, компілятор включає різні види оптимізації в залежності від типу об’єкту.


Зв’язані теми