Имеет ли виртуальное ключевое слово с 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
как имя функции не говорит много, и если ваши классы в основном являются функциями модели, это может показаться разумным выбором.