указатели на функции — простой сигнал для кнопки в переполнении стека

Я смотрел на несколько реализаций сигнала / слота, и без исключения они были довольно сложными, некоторые даже полагались на MOC и дополнительную генерацию кода, как в Qt.

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

typedef void (*fPtr)();

class GenericButton
{
public:
GenericButton() : funcitonToCall(nullptr) {}
void setTarget(fPtr target) {
funcitonToCall = target;
}

void pressButton() {
if (funcitonToCall) funcitonToCall();
}

private:
fPtr funcitonToCall;
};

void doSomething(){
std::cout << "doing something..." << std::endl;
}

void doSomethingElse(){
std::cout << "doing something else..." << std::endl;
}

int main(){
GenericButton myButton;
myButton.setTarget(doSomething);
myButton.pressButton();
myButton.setTarget(doSomethingElse);
myButton.pressButton();
}

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

2

Решение

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

#include <iostream>
#include <functional>

using namespace std::placeholders;class GenericButton
{
public:
typedef std::function<void()> fPtr;
GenericButton() : funcitonToCall(nullptr) {}
void setTarget(fPtr target) {
funcitonToCall = target;
}

void pressButton() {
if (funcitonToCall) funcitonToCall();
}

private:
fPtr funcitonToCall;
};

struct foo {
void doSomething() const {
std::cout << "doing something in a foo..." << std::endl;
}

static void alternative(int i) {
std::cout << "And another, i=" << i << "\n";
}
};

void doSomethingElse() {
std::cout << "doing something else..." << std::endl;
}

int main() {
GenericButton myButton;
foo f;
myButton.setTarget(std::bind(&foo::doSomething, &f));
myButton.pressButton();
myButton.setTarget(doSomethingElse);
myButton.pressButton();
myButton.setTarget(std::bind(foo::alternative, 666));
myButton.pressButton();
myButton.setTarget([](){ std::cout << "Lambda!\n"; });
myButton.pressButton();
}

Почти всегда лучшее решение в C ++, чем указатели на функции.

Если у вас нет std::function/std::bind всегда есть альтернативы в ускорении этой работы, и вы можете свернуть свой собственный std::function Альтернатива без лишней работы, которую стоило бы сделать, если вы хотите сделать что-то подобное.

Большинство механизмов сигналов / слотов, которые существуют около того времени, когда такие вещи, как boost::bind не был жизнеспособным вариантом. Эти дни давно прошли, и вы можете получить что-то стандартное и более гибкое для чуть большей сложности, чем просто указатель на функцию.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]