[英]C++: Store pointer to a member function of an object in another object
我有一個類,它將在某些情況下調用用戶指定的功能。 因此,該類具有方法void setExternalPostPaintFunction(void(*function)(QPainter&));
可以用來“注冊”功能。 然后將在這種情況下調用此函數:
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
時才推導,因此我無法擁有依賴於此類型的成員變量,因為我的成員變量的類型具有要知道創建對象的時間,除此之外不能更改,但是必須在分配了新功能的情況下(可能是不同類型對象的成員功能)。
那么執行此操作的正確方法是什么? 我不太適合使用模板和函數指針,因此我可能忽略了一些東西。
另一個選擇當然是使用虛擬成員函數創建函子類,該成員函數可以在派生類中被覆蓋,然后通過+存儲該類型的對象指針而不是函數指針。 但是,如果有可能,我會以某種方式更喜歡我的方法。
編輯:解決方案
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);
奇跡般有效。
您可以使用std::function
:
class A {
public:
//PostPaintFun can be anything which acts as a function taking a QPainter&
//Could be a lambda, function pointer, functor, etc.
using PostPaintFun = std::function<void(QPainter&)>;
void setExternalPostPaintFunction(PostPaintFun fun);
private:
//Names beginning with an underscore are reserved, don't use them
//Ending with an underscore is fine
PostPaintFun fun_;
bool externalPostPaintFunctionAssigned_;
};
現在,您可以像這樣使用成員函數:
struct B
{
void exec(QPainter&) const;
};
void foo() {
B b;
a.setExternalPostPaintFunction(
[b] (QPainter& p) {b.exec(p);}
);
}
//or inside B
void B::foo() {
a.setExternalPostPaintFunction(
[this] (QPainter&p) {this->exec(p);}
);
}
我不得不說我更喜歡TartanLlama的答案,但是在這里您可以使用一些適合您的東西。
這可能需要一些工作,但是我相信您會明白的。
struct IFunctionHolder {}; // Used for pointing to any FunctionHolder
typedef IFunctionHolder* functionHolder_ptr; // Alias for IFunctionHolder* .
template<typename Function> // The template for the actual function holders.
struct FunctionHolder: public IFunctionHolder
{
Function function;
};
class A {
public:
template <typename T>
void setExternalPostPaintFunction(void(T::*function)(QPainter&), T* object);
private:
functionHolder_ptr *function_holder; // This memeber can hold eny instantiation of template<> FunctionHolder.
// Instantiate this member wen calling setExternalPostPaintFunction
bool _externalPostPaintFunctionAssigned;
};
您可能會有類似以下的代碼:
A some_a;
void some_a.setExternalPostPaintFunction(&SomeInstance::some_fnunction); // Here take place the instantiation of FunctionHolder.
some_a.function_holder.function(some_painter);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.