Проблема с перегрузкой оператора - PullRequest
1 голос
/ 13 сентября 2010

В чем проблема с этим кодом? этот код дает мне много синтаксических ошибок. Также мне хотелось бы знать, почему функторы используются в C ++.

class f
{
public:
    int operator(int a) {return a;}
} obj;

int main()
{
    cout << obj(0) << endl;
}

Ответы [ 6 ]

7 голосов
/ 13 сентября 2010

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

int operator()(int a) {return a;}

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

Для довольно сложного примера того, как вы можете использовать функциональные объекты, взгляните на шаблоны выражений.

Вот небольшой, несколько надуманный пример того, как они могут использовать наследование:

struct unary_int_func {
    virtual int operator()(int i) = 0;
};
struct negate : public unary_int_func {
    int operator()(int i) {return -i;}
};
struct one_plus : public unary_int_func {
    int operator()(int i) {return i+1;}
};

void show_it(unary_int_func &op, int v) {
    cout << op(v) << endl;
}

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

struct a_different_base_class {
    virtual int operator()(int i) = 0;
};

но экземпляры этого не будут взаимозаменяемы с экземплярами unary_int_func.

Что касается состояния, рассмотрим функцию бегущей суммы:

struct running_sum : public unary_int_func {
    int total;
    running_sum() : total(0) {}
    int operator()(int i) {return total += i;}
};

int main()
{
    running_sum s;
    cout << s(1) << endl;
    cout << s(2) << endl;
    cout << s(3) << endl;
    cout << s(4) << endl;
}

Здесь экземпляр running_sum отслеживает общее количество. Он выведет 1, 3, 6 и 10. Указатели на функции не имеют такого способа сохранения состояния между различными вызовами. Страница SGI STL по функциональным объектам имеет аналогичный пример с моей текущей суммой, но показывает, как вы можете легко применить ее к ряду элементов в контейнере.

0 голосов
/ 13 сентября 2010

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

Поскольку функтор является объектом, применяются правила наследования, и вы можете использовать это в своих интересах.

Функтор также полезен при использовании STL. std :: sort, std :: for_each и т. д. позволяют обрабатывать содержимое всего контейнера (включая массивы). Вот пример из cplusplus.com:

// for_each example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

void myfunction (int i) {
  cout << " " << i;
}

struct myclass {
  void operator() (int i) {cout << " " << i;}
} myobject;

int main () {
  vector<int> myvector;
  myvector.push_back(10);
  myvector.push_back(20);
  myvector.push_back(30);

  cout << "myvector contains:";
  for_each (myvector.begin(), myvector.end(), myfunction);

  // or:
  cout << "\nmyvector contains:";
  for_each (myvector.begin(), myvector.end(), myobject);

  cout << endl;

  return 0;
}
0 голосов
/ 13 сентября 2010

Поскольку вы уже выяснили проблему в коде перегрузки вашего оператора, я бы скорее попытался ответить на ваши сомнения относительно функторов.

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

0 голосов
/ 13 сентября 2010

Функторы - это в основном функции с состояниями.Их наибольшее использование в библиотеках STL и Boost.Например, std :: sort принимает тип функтора с именем Comparator.В этом контексте, возможно, функциональный объект мог бы быть передан вместо этого, но функтор предлагает большую гибкость посредством элементов данных, которые вы можете иметь, и манипулировать ими с последующими вызовами того же функтора.Функторы также используются для реализации обратных вызовов C ++.

0 голосов
/ 13 сентября 2010

потому что int operator(int) фактически равно int int #something_missing_here#(int)

operator является зарезервированным ключевым словом, а не квалификатором в качестве действительного идентификатора / имени функции, если используется отдельно.
Я бы сказал, что он используется для того, чтобы компилятор понял, что данное выражение является объявлением функции, несмотря на то, что используются недопустимые идентификаторы (c ++ допускает только алфавит и подчеркивание в качестве первого символа в именовании)

0 голосов
/ 13 сентября 2010

Попробуйте это:

class f
{

  public:

   int operator(int a) {return a;}

};

int main()
{
  f obj;
  cout<<obj(0)<<endl;

}
...