Почему оператор переопределения ()?

51
задан John Carter 5 October 2011 в 16:30
поделиться

11 ответов

Одна из основной цели при перегрузке оператора () состоит в том, чтобы создать функтор. Функтор действует точно так же, как функция, но он имеет преимущества, что это с сохранением информации, означая его, может сохранить данные, отражающие его состояние между вызовами.

Вот простой пример функтора:

struct Accumulator
{
    int counter = 0;
    int operator()(int i) { return counter += i; }
}
...
Accumulator acc;
cout << acc(10) << endl; //prints "10"
cout << acc(20) << endl; //prints "30"

Функторы в большой степени используются с универсальным программированием. Много алгоритмов STL записаны очень общим способом, так, чтобы Вы могли плагин Ваша собственная функция/функтор в алгоритм. Например, станд. алгоритма:: for_each позволяет Вам применять операцию на каждый элемент диапазона. Это могло быть реализовано что-то как этот:

template <typename InputIterator, typename Functor>
void for_each(InputIterator first, InputIterator last, Functor f)
{
    while (first != last) f(*first++);
}

Вы видите, что этот алгоритм очень универсален, так как он параметризован функцией. При помощи оператора (), эта функция позволяет Вам использовать или функтор или указатель функции. Вот пример, показывающий обе возможности:

void print(int i) { std::cout << i << std::endl; }
...    
std::vector<int> vec;
// Fill vec

// Using a functor
Accumulator acc;
std::for_each(vec.begin(), vec.end(), acc);
// acc.counter contains the sum of all elements of the vector

// Using a function pointer
std::for_each(vec.begin(), vec.end(), print); // prints all elements
<час>

Относительно Вашего вопроса об операторе () перегрузка, хорошо да это возможно. Можно отлично записать функтор, который имеет несколько операторов скобки, пока Вы уважаете основные правила перегрузки метода (например, перегрузка только на типе возврата не возможна).

135
ответ дан jacknad 7 November 2019 в 09:43
поделиться

Это позволяет классу действовать как функция. Я использовал его в регистрирующемся классе, где вызов должен быть функцией, но я хотел дополнительное преимущество класса.

так что-то вроде этого:

logger.log("Log this message");

превращается в это:

logger("Log this message");
25
ответ дан Lodle 7 November 2019 в 09:43
поделиться

Многие ответили, что это делает функтор, не говоря одну большую причину, почему функтор лучше, чем простая функция.

ответ - то, что функтор может иметь состояние. Рассмотрите функцию подведения итогов - это должно сохранить рабочее общее количество.

class Sum
{
public:
    Sum() : m_total(0)
    {
    }
    void operator()(int value)
    {
        m_total += value;
    }
    int m_total;
};
5
ответ дан Mark Ransom 7 November 2019 в 09:43
поделиться

Функтор не является функцией, таким образом, Вы не можете перегрузить его.
Ваш коллега корректен, хотя это, перегрузка оператора () используется для создания "функторов" - объекты, которые можно назвать как функции. В сочетании с шаблонами, ожидающими "подобные функции" аргументы, это может быть довольно мощно, потому что различие между объектом и функцией становится размытым.

, Поскольку в других плакатах было сказано: функторы имеют преимущество перед простыми функциями, в которых у них может быть состояние. Это состояние может использоваться по единственному повторению (например, для вычисления суммы всех элементов в контейнере) или по нескольким повторениям (например, для нахождения всех элементов в нескольких контейнерах, удовлетворяющих конкретные критерии).

4
ответ дан Joris Timmermans 7 November 2019 в 09:43
поделиться

Начните использовать std::for_each, std::find_if, и т.д. чаще в Вашем коде, и Вы будете видеть, почему удобно иметь способность перегрузиться () оператор. Это также позволяет функторам и задачам иметь ясный вызывающий метод, который не будет конфликтовать с названиями других методов в производных классах.

3
ответ дан Michel 7 November 2019 в 09:43
поделиться

Можно также просмотреть Матричный пример часто задаваемых вопросов C++ . Существует хорошее использование для того, чтобы сделать его, но это, конечно, зависит от того, что Вы пытаетесь выполнить.

3
ответ дан carson 7 November 2019 в 09:43
поделиться

Функторы похожи на в основном указатели функции. Они обычно предназначаются, чтобы быть copyable (как указатели функции) и вызываются таким же образом как указатели функции. Основное преимущество - то, что, когда у Вас есть алгоритм, который работает с шаблонным функтором, вызов функции к оператору () может быть встроен. Однако указатели функции являются все еще допустимыми функторами.

2
ответ дан Greg Rogers 7 November 2019 в 09:43
поделиться

Использование оператора () для формирования функторы в C++ связаны с функциональное программирование парадигмы, которые обычно используют подобное понятие: закрытия .

2
ответ дан Judge Maygarden 7 November 2019 в 09:43
поделиться

Одна сила I видит, однако это может быть обсуждено, то, что подпись оператора () смотрит и ведет себя то же через различные типы. Если у нас был класс Генератор отчетов, который имел членский отчет метода (..), и затем другой класс Писатель, который имел членскую запись метода (..), мы должны были бы записать адаптеры, если мы хотели бы использовать оба класса как, возможно, шаблонный компонент некоторой другой системы. Все, о чем это заботилось бы, должно передать строки или что имеет Вас. Без использования оператора () перегрузка или запись специальных адаптеров типа, Вы не могли сделать материала как

T t;
t.write("Hello world");

, потому что T имеет требование, чтобы была функция членства, названная записью, которая принимает что-либо неявно castable к символу константы* (или скорее символу константы []). Класс Генератора отчетов в этом примере не имеет этого, таким образом имея T (шаблонный параметр), быть Генератором отчетов не удалось бы скомпилировать.

Однако, поскольку далеко я вижу, что это работало бы с различными типами

T t;
t("Hello world");

, хотя, это все еще явно требует, чтобы типу T определили такой оператор, таким образом, у нас все еще есть требование к T. Лично, я не думаю, что это слишком странно с функторами, поскольку они являются наиболее часто используемыми, но я видел бы другие механизмы для этого поведения. На языках как C# Вы могли просто передать в делегате. Я не слишком знаком с указателями функции членства в C++, но я мог предположить, что Вы могли достигнуть того же поведения там также.

Кроме синтетического сахарного поведения я действительно не вижу преимуществ оператора, перегружающегося для выполнения таких задач.

я уверен, что существуют более сознательно люди, у которых есть лучшие причины, чем я имею, но я думал, что размечу свое мнение для остальной части Вас для совместного использования.

2
ответ дан Statement 7 November 2019 в 09:43
поделиться

Другой коллега указал, что это мог быть способ замаскировать объекты функтора как функции. Например, это:

my_functor();

действительно:

my_functor.operator()();

Так делает это означает это:

my_functor(int n, float f){ ... };

Может использоваться для перегрузки этого также?

my_functor.operator()(int n, float f){ ... };
1
ответ дан JeffV 7 November 2019 в 09:43
поделиться

Другие сообщения сделали хорошее задание, описывающее, как оператор () работает и почему это может быть полезно.

я недавно использовал некоторый код, который делает очень широкое применение оператора (). Недостаток перегрузки этого оператора - то, что некоторые IDE становятся менее эффективными инструментами в результате. В Visual Studio можно обычно щелкать правой кнопкой по вызову метода для движения в определение метода и/или объявление. К сожалению, VS не достаточно умен для индексации оператора () вызовы. Особенно в сложном коде с переопределенным оператором () определения повсеместно, может быть очень трудно выяснить то, что часть кода выполняет где. В нескольких случаях я нашел, что должен был выполнить код и трассировку через него для нахождения то, что на самом деле работало.

1
ответ дан Mr Fooz 7 November 2019 в 09:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: