У меня есть класс, который должен вызывать функцию, указанную пользователем в определенных случаях. Поэтому класс имеет метод void setExternalPostPaintFunction(void(*function)(QPainter&));
, который может использоваться для «регистрации» функции. Затем эта функция будет вызываться по этому поводу:C++: Сохранить указатель на функцию-член объекта в другом объекте
class A {
public:
void setExternalPostPaintFunction(void(*function)(QPainter&));
private:
void (*_externalPostPaint)(QPainter&);
bool _externalPostPaintFunctionAssigned;
};
Указатель функции сохраняется в переменной-члене _externalPostPaint
. Реализация setExternalPostPaintFunction
выглядит следующим образом:
void A::setExternalPostPaintFunction(void(*function)(QPainter&)) {
_externalPostPaint = function;
_externalPostPaintFunctionAssigned = true;
}
Теперь, это работает с нормальными функциями. Тем не менее, я хочу иметь возможность также передавать указатели на функции-члены объектов. Из того, что я знаю, мне также нужно передать и сохранить указатель на объект в этом случае. Однако я не знаю, какой тип будет иметь другой объект. Поэтому я предполагаю, что я вынужден использовать шаблоны. Я уже думал, что-то вроде этого:
class A {
public:
template <typename T>
void setExternalPostPaintFunction(void(T::*function)(QPainter&), T* object);
private:
void (T::*_externalPostPaint)(QPainter&); //<- This can't work!
bool _externalPostPaintFunctionAssigned;
};
Таким образом, я могу передать указатель на функцию и указатель на объект setExternalPostPaintFunction
и, вероятно, будет в состоянии вызвать функцию на объект внутри этой функции. Но я не могу сохранить его в переменной _externalPostPaint
, потому что тип T
выведен только при вызове функции setExternalPostPaintFunction
, поэтому я не могу иметь переменную-член, которая зависит от этого типа, поскольку тип моей переменной-члена имеет чтобы быть известным, когда объект создан, и, кроме того, он не может измениться, но он будет иметь место в случае, когда назначается новая функция, которая, возможно, может быть функцией-членом объекта другого типа.
Итак, каков правильный способ сделать это, или нет? Я не очень хорошо разбираюсь в шаблонах и указателях функций, поэтому я мог бы что-то упустить.
Параметр Anoter, безусловно, должен был бы создать класс функтора с функцией виртуального члена, который может быть перезаписан в производном классе, а затем передать + сохранить указатель объекта этого типа вместо указателя функции. Но я как-то предпочел бы мой подход, если это возможно.
EDIT: РЕШЕНИЕ
TartanLlama привел меня на правильном пути, предложив использовать std::function
. Вот как я ее решил:
class A {
public:
template <typename T>
void setExternalPostPaintFunction(T* object, void(T::*function)(QPainter&)) {
_externalPostPaint = std::bind(function, object, std::placeholders::_1);
_externalPostPaintFunctionAssigned = true;
}
void setExternalPostPaintFunction(std::function<void(QPainter&)> const& function);
private:
std::function<void(QPainter&)> _externalPostPaint;
bool _externalPostPaintFunctionAssigned;
};
Как вы видите, указатель на функцию функции/члена хранится в std::function<void(QPainter&)>
объекта в настоящее время. Преимущество состоит в том, что std::function
может в основном хранить любую вызываемую цель. Затем есть две перегрузки: одна, которая может использоваться для любого объекта std::function
, который также принимает, например. нормальный указатель функции (потому что std::function
, который, как ожидается, затем неявно построен из этого), и один для функций-членов, которые должны быть вызваны на объект (более для удобства). Последний реализован как шаблон. Это использует std::bind
для создания объекта std::function
вызова этой функции-члена (пользователь передал) на объект (пользователь прошел).
Перегрузка, которая принимает std::function
реализуется в исходном файле так:
void ImageView::setExternalPostPaintFunction(std::function<void(QPainter&)> const& function) {
_externalPostPaint = function;
_externalPostPaintFunctionAssigned = true;
}
Вызов этой хранимой функции в коде класса A
теперь так же просто, как:
//canvas is a QPainter instance
if (_externalPostPaintFunctionAssigned) _externalPostPaint(canvas);
Пользователь, который хочет зарегистрировать функцию-член как функцию обратного вызова, должен сделать следующее:
//_imageView is an instance of "A"
//"MainInterface" is the type of "this"
_imageView->setExternalPostPaintFunction(this, &MainInterface::infoPaintFunction);
Или, если это не функция-член, а просто нормальная функция:
void someFunction(QPainter& painter) {
//do stuff
}
_imageView->setExternalPostPaintFunction(&someFunction);
Или он может явно создать std::function
объект и передать его:
std::function<void(QPainter&)> function = [&](QPainter& painter){ this->infoPaintFunction(painter); };
_imageView->setExternalPostPaintFunction(function);
работает как шарм.
Является ли C++ 11 хорошо? 'std :: function' идеально подходит для такого рода вещей. – TartanLlama
Да, C++ 11 в порядке. Я посмотрю на это. – user1488118