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

 


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