C++. Перевантаження оператору () виклику функції. Приклади

Перевантаження оператору () виклику функції. Приклади


Зміст


1. Особливості перевантаження оператору () виклику функції. Операторна функція operator()(). Загальна форма

Оператор виклику функції може бути перевантажений. У цьому випадку у класі створюється операторна функція operator()(). Ця функція може приймати довільну кількість параметрів

Загальна форма реалізації операторної функції, що перевантажує оператор operator()() наступна.
Якщо у деякому класі з іменем ClassName перевантажена операторна функція operator()()

class ClassName
{
    // ...

    return_type operator()(parameters)
    {
        // ...
    }
};

то при виклику в іншому коді об’єкту з іменем obj класу ClassName

ClassName obj;
obj(parameters);

цей виклик буде перетворено в наступний виклик операторної функції

obj.operator()(parameters);

тут

  • ClassName – ім’я класу, в якому реалізована операторна функція operator()();
  • return_type – тип, який повертає операторна функція operator()();
  • parameters – параметри, які отримує операторна функція operator()();
  • obj – екземпляр (об’єкт) класу ClassName.

 

2. Скільки параметрів може приймати операторна функція operator()(), яка перевантажує оператор виклику функції?

Операторна функція operator()() може приймати будь-яку кількість параметрів. Операторна функція operator()() може бути без параметрів.



 

3. Приклади перевантаження оператору () виклику функції

Приклад 1. Задано клас SqEqual, що містить усі дані та методи для розв‘язку квадратного рівняння.

У класі SqEqual реалізовано

  • внутрішні приховані (private) дані a, b, c, x1, x2 для рішення задачі;
  • конструктор класу;
  • внутрішня прихована (private) функція Solution(), в якій реалізовано алгоритм розв’язку квадратного рівняння. Ця функція викликається з інших методів та операторних функцій класу;
  • загальнодоступні (public) методи GetSolution() та GetSolutionP(), які викликають функцію Solution() для розв’язку квадратного рівняння. Ці методи можна викликати з екземпляру класу. Методи реалізовані з метою демонстрації передачі параметрів за посиланням та за покажчиком;
  • дві перевантажені загальнодоступні операторні функції operator()(), які можна викликати для отримання розв’язку квадратного рівняння. Функції отримують різну кількість параметрів, тому вони сприймаються компілятором як різні функції. Функція operator()() з двома параметрами в якості коефіцієнтів рівняння використовує значення внутрішніх прихованих (private) змінних класу a, b, c. Функція operator()() з п’ятьма параметрами для розв’язку використовує вхідні параметри a, b, c.

Текст програми, що містить реалізацію класу SqEqual, створеної за шаблоном Console Application наступний

#include <iostream>
using namespace std;

// клас, що реалізує дані та методи розв'язку квадратного рівняння
class SqEqual
{
private:
    // коефіцієнти квадратного рівняння
    double a;
    double b;
    double c;

    // корені - розв'язки
    double x1;
    double x2;

    // внутрішній метод розв'язку квадратного рівняння
    bool Solution(void)
    {
        double d; // дискримінант

        // чи взагалі є рівняння?
        if (a==0)
            return false;

        d = b*b-4*a*c;

        if (d>=0)
        {
            // є розв'язок рівняння
            x1 = (-b - sqrt(d)) / (2*a);
            x2 = (-b + sqrt(d)) / (2*a);
        }
        else
            return false; // рівняння не має розв'язку

        return true; // є розв'язок в змінних x1, x2
    }

public:
    // конструктор класу
    SqEqual(double a, double b, double c)
    {
        this->a = a;
        this->b = b;
        this->c = c;
    }

    // загальнодоступні методи розв'язку квадратного рівняння
    bool GetSolution(double& x1, double& x2)
    {
        if (Solution()) // викликати внутрішній метод розв'язку
        {
            x1 = this->x1;
            x2 = this->x2;
            return true; // є розв'язок
        }

        return false; // немає розв'язку
    }

    bool GetSolutionP(double* x1, double* x2)
    {
        if (Solution())
        {
            *x1 = this->x1;
            *x2 = this->x2;
            return true; // є розв'язок
        }
        return false; // немає розв'язку
    }

    // операторна функція operator()(), що розв'язує квадратне рівняння
    // операторна функція отримує 5 параметрів
    // функція повертає true, якщо рівняння має розв'язок,
    // x1, x2 - розв'язок рівняння, передаються за покажчиком
    bool operator()(double a, double b, double c, double* x1, double* x2)
    {
        this->a = a;
        this->b = b;
        this->c = c;

        if (Solution())
        {
            *x1 = this->x1;
            *x2 = this->x2;
            return true;
        }
        return false;
    }

    // варіант 2 - операторна функція отримує тільки 2 параметри, що є розв'язком
    // x1, x2 - передаються як посилання
    bool operator()(double& x1, double& x2)
    {
        // коефіцієнти a, b, c отримуються з поточного об'єкту
        if (Solution())
        {
            x1 = this->x1;
            x2 = this->x2;
            return true; // є рішення
        }

        return false; // рівняння немає розв'язку
    }
};

void main(void)
{
    // перевантаження оператора () виклику функції
    double a = 2, b = -3, c = 1;
    SqEqual e(a, b, c); // створити екземпляр
    double x1, x2;
    bool f;

    // виклик операторної функції operator()() з двома параметрами
    f = e(x1,x2);

    if (f)
    {
        // якщо є рішення рівняння 2*x^2 - 3*x + 1 = 0, то вивести результат
        cout << a << "* x^2 + (" << b << ") * x + (" << c << ") = 0" << endl;
        cout << "x1 = " << x1 << endl;
        cout << "x2 = " << x2 << endl << endl;
    }

    // виклик операторної функції з 5 параметрами
    f = e(5, -7, 2, &x1, &x2);

    if (f)
    {
        // якщо є рішення рівняння, то вивести результат
        cout << "5 * x^2 - 7*x + 2 = 0" << endl;
        cout << "x1 = " << x1 << endl;
        cout << "x2 = " << x2 << endl << endl;
    }
}

Як видно з вищенаведеного коду, у функції main() виклик операторної функції operator()() з двома параметрами наступний

f = e(x1, x2);

Якщо рівняння має розв’язок, то змінні x1 та x2 будуть мати відповідні значення. У цій операторній функції передача значень у змінні x1, x2 відбувається за посиланням.

Виклик операторної функції operator()() з п’ятьма параметрами наступний

f = e(5, -7, 2, &x1, &x2);

У цьому випадку у функцію передаються адреси змінних x1, x2. У функції доступ до змінних відбувається за покажчиком.

Результат виконання програми

2* x^2 + (-3) * x + (1) = 0
x1 = 0.5
x2 = 1

5 * x^2 - 7*x + 2 = 0
x1 = 0.4
x2 = 1

Приклад 2. Нехай задано клас Point, що реалізує точку на координатній площині.

У класі Point оголошуються:

  • внутрішні приховані (private) змінні x, y;
  • конструктор класу, який ініціалізує нульовими значеннями значення змінних x, y;
  • методи доступу до внутрішніх змінних SetP(), GetX(), GetY();
  • перевантажена операторна функція operator()() без параметрів. Ця функція повертає поточний об’єкт (екземпляр) класу;
  • перевантажена операторна функція operator()() з двома параметрами. Ця функція повертає поточний екземпляр класу, значення внутрішніх змінних x, y якого рівні значенню відповідних параметрів _x, _y.

Реалізація класу Point наступна:

// клас, що реалізує точку
class Point
{
private:
    int x, y;

public:
    Point()
    {
        x = y = 0;
    }

    // методи доступу
    void SetP(int _x, int _y)
    {
        x = _x;
        y = _y;
    }

    int GetX() { return x; }
    int GetY() { return y; }

    // перевантаження операторної функції operator()() без параметрів
    Point operator()()
    {
        return *this; // повернути поточний об'єкт
    }

    // перевантаження операторної функції operator()() з двома параметрами
    Point operator()(int _x, int _y)
    {
        x = _x;
        y = _y;
        return *this;
    }
};

Використання операторної функції operator()() класу Point в іншому методі може бути, наприклад, таким

// перевантаження оператора () виклику функції
Point p1; // створити об'єкт
int t;

p1.SetP(3,5); // встановити значення

Point p2; // новий об'єкт

// виклик операторної функції без параметрів
p2 = p1();

// перевірка
t = p2.GetX(); // t = 3
t = p2.GetY(); // t = 5

// виклик операторної функції operator()() з двома параметрами
p2 = p1(7,8);

// перевірка
t = p2.GetX(); // t = 7
t = p2.GetY(); // t = 8

Як видно з вищенаведеного прикладу, операторна функція operator()() може мати декілька реалізацій в класі. Ці реалізації повинні відрізнятися кількістю або типами параметрів, які передаються в операторну функцію.

 

4. Приклад використання операторної функції operator()() яка використовується у поєднанні з іншою операторною функцією operator+()

У прикладі оголошується клас Complex, в якому перевантажуються:

  • оператор виклику функції ( );
  • оператор додавання +, який здійснює додавання комплексних чисел.

У класі Complex реалізовано наступні елементи:

  • внутрішні приховані (private) змінні real та imag. Ці змінні визначають дійсну та уявну частину комплексного числа;
  • два конструктори;
  • методи GetI() та GetR() для читання значень внутрішніх змінних real та imag;
  • операторна функція operator+(), яка переваантажує оператор +. Функція сумує два екземпляри (об’єкти) класу Complex;
  • операторна функція operator()(), яка перевантажує оператор виклику функції (). Функція створює екземпляр класу Complex на основі вхідних параметрів.

Текст програми типу Console Application, що демонструє реалізацію класу Complex наступний

#include <iostream>
using namespace std;

// клас, що реалізує комплексне число
class Complex
{
private:
    double real; // дійсна частина комплексного числа
    double imag; // уявна частина

public:
    // конструктори
    Complex()
    {
        real = imag = 0;
    }

    Complex(double real, double imag)
    {
        this->real = real;
        this->imag = imag;
    }

    // методи доступу
    double GetI() { return imag; }
    double GetR() { return real; }

    // перевантажений оператор додавання +
    Complex operator+(Complex c)
    {
        // додавання комплексних чисел
        return Complex(real + c.real, imag + c.imag);
    }

    // перевантажений оператор виклику функції
    Complex operator()(double real, double imag)
    {
        this->real = real;
        this->imag = imag;
        return *this;
    }
};

void main()
{
    Complex c1(3, 4);
    Complex c2;
    Complex c3;
    double r, i;

    // виклик операторних функцій operator+() та operator()()
    c3 = c1 + c2(5, 6); // c3 = c1.operator+(c2.operator(5,6))

    // перевірка
    r = c3.GetR(); // r = 3 + 5 = 8
    i = c3.GetI(); // i = 4 + 6 = 10

    cout << "r = " << r << endl;
    cout << "i = " << i;
}

Результат виконання програми

r = 8
i = 10

 


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