Имеет ли виртуальное ключевое слово с operator()() смысл? (функторы)

У меня есть иерархия, определенная ниже

class Strategy
{
public:
    virtual void Run();
};
class StrategyA : public Strategy
{
public:
    virtual void Run();
};
class StrategyB : public Strategy
{
public:
    virtual void Run();
};

Мне было интересно, заменил ли оператор Run() оператором() смысл и если есть какие-то преимущества с точки зрения дизайна и эффективности.

class Strategy
{
public:
    virtual void operator()();
};
class StrategyA : public Strategy
{
public:
    virtual void operator()();
};
class StrategyB : public Strategy
{
public:
    virtual void operator()();
};

Спасибо

CV.

Ответ 1

Да. Это в полной мере имеет смысл.

Любая перегрузка оператора - это, в конце концов, функция. Он добавляет синтаксический сахар к языку. Иногда они необходимы, но часто это просто синтаксический сахар.

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

  • с использованием указателя базового типа и
  • с использованием ссылки базового типа

Пример (демонстрация),

struct A
{
   virtual void operator()() { cout << "A" << endl; }
};
struct B : A
{
   virtual void operator()() { cout << "B" << endl; }
};

int main() {
        B b;

        //using pointer
        A *ptr = &b;
        (*ptr)(); //clumsy!  - prints B

        //using reference
        A &ref = b;
        ref();   //better    - prints B

        //also correct
        b();  //prints B
        return 0;
}

И если у вас есть шаблон функции, написанный как:

template<typename Functor>
void call(Functor fun)
{
   (*fun)();
}

Затем вы можете использовать эту функцию для функторов и регулярных функций:

void regular_function()
{
   cout << "regular_function" << endl;
}

B b;
call(&b);  //prints B
call(regular_function); //prints regular_function

Демо: http://ideone.com/B9w16

Ответ 2

Как уже было сказано, да, вы можете.

Дополнительная информация ниже для возможного тай-брейка.

В случае виртуальных методов у вас будет доступ к объектам, набранным как Strategy & или Стратегии *. Если вы используете ссылки, а не указатели, вам не нужно читать следующее. В противном случае это может представлять интерес и в пользу виртуального метода с именем.

StrategyA sA;
Strategy& s = sA;

s.Run(); //correct and readable
s(); //just as correct and readable

Strategy* ptr_s = &sA;
ptr_s->Run(); //correct and readable
(*ptr_s)(); // still correct but a bit clumsy

Ответ 3

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

Ответ 4

Да, operator() - это просто специальное имя функции. Он также может быть virtual как Run().

Ответ 5

Я не понимаю, почему нет. За исключением конкретных контекстов Run как имя функции не говорит много, и если ваши классы в основном являются функциями модели, это может показаться разумным выбором.