Имеет ли смысл виртуальное ключевое слово с operator () ()?(функторы) - PullRequest
12 голосов
/ 13 сентября 2011

Считайте, что у меня есть иерархия, определенная как ниже

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

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

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

Спасибо

CV.

Ответы [ 5 ]

11 голосов
/ 13 сентября 2011

Да.Это полностью имеет смысл.

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

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

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

Пример ( demo ),

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

5 голосов
/ 13 сентября 2011

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

Дополнительная информация о возможном разрыве связей ниже.

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

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 голосов
/ 13 сентября 2011

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

3 голосов
/ 13 сентября 2011

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

1 голос
/ 13 сентября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...