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() для решения квадратного уравнения. Эти методы можно вызывать из экземпляра класса. Методы реализованы с целью демонстрации передачи параметров по ссылке и по указателю;
  • две перегруженные общедоступные (public) операторные функции 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*x2-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.Set(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

  ⇑


Связанные темы

  ⇑