【问题标题】:function pointer array with class functions of different classes具有不同类的类函数的函数指针数组
【发布时间】:2018-01-21 13:04:52
【问题描述】:

SomeClass.h

class SomeClass{
    public:
        static std::vector<void (*)()> UpdateFuncs;
}

OtherClass.h

class OtherClass{
    private:
        void Update();
    public:
        OtherClass();
}

OtherClass.cpp

OtherClass::OtherClass(){
    Time::UpdateFuncs.push_back(&(this->Update));
}

在构建时我得到'&amp;':对绑定成员函数表达式的非法操作 如果我这样做:

.push_back(&Update);

然后我得到“没有重载函数的实例

std::vector<_ty _alloc>::push_back [with _Ty=void (*)(), _Alloc=std::allocator]" 匹配参数列表"

提前致谢

【问题讨论】:

  • &amp;Update 不是void (*)()。此代码无法工作。你有什么问题?
  • 我的问题是如何更改更新以使其正常工作
  • 您必须使 Update static 获得该类型。
  • 你想解决什么问题? Update 是一个非静态成员,它有一个隐含的 this 参数。您希望如何在呼叫现场提供它?

标签: c++ pointers function-pointers


【解决方案1】:

OtherClass::Update 不适用于void (*)() 函数指针,因为它是一个非静态成员函数;就好像它有一个“不可见的”OtherClass* 参数。

使用std::function 实现您的目标:

#include <functional>

class Time
{
public:
    static std::vector<std::function<void()>> UpdateFuncs;
};

在 OtherClass.cpp 中,使用 this-capturing lamba 作为函数对象:

OtherClass::OtherClass()
{
    Time::UpdateFuncs.push_back([this] { Update(); });
}

当然,如果您将Update 设为静态,那么您仍然可以使用void (*)(),因为“invisible”参数已被删除,但std::function 只是安全且现代的方法它。

【讨论】:

  • 太棒了!我没有立即意识到 OP 不仅需要函数指针,还需要目标对象。我只有一个问题:每个创建的OtherClass 都会有一个函数在向量中引用它;但是如何找到与要删除的对象相对应的条目以便将其从向量中删除?
  • @Christophe:这个问题太宽泛了......这完全取决于程序逻辑的其余部分是否、如何、何时以及由谁删除对象。
【解决方案2】:

问题

您尝试将void(OtherClass::*)() 类型的成员函数指针分配给void(*)() 类型的普通函数指针。

很遗憾这两种类型是不兼容的:普通函数只能用参数调用,成员函数指针只能针对特定对象调用。

第一种解决方案:成员函数指针

您必须更改向量的定义以使其使用成员函数指针。

class OtherClass;  // forward deaclaration
class SomeClass {
public:
    static std::vector<void (OtherClass::*)()> UpdateFuncs;
};

那么就可以按预期回退函数了:

OtherClass::OtherClass() {
    SomeClass::UpdateFuncs.push_back(&OtherClass::Update);
}

Online demo

不幸的是,您不能将它与指向其他类的成员函数指针或普通函数指针混合使用。而且您必须在调用函数时指定要使用的对象。

更好的解决方案:命令模式

command pattern 比函数指针更灵活。由于命令的特殊化,您可以混合调用普通函数指针、不同类的成员函数指针或 ad-hoc 函数的命令。

命令可能如下所示:

class Command {
public: 
    virtual void execute() = 0; 
    virtual ~Command();
}; 

class CommandOtherClass : public Command { 
    OtherClass *target; 
    void (OtherClass::*f)(); 
public: 
    CommandOtherClass (void (OtherClass::*fct)(), OtherClass*t); 
    void execute() override; 
};

实现非常简单:

CommandOtherClass::CommandOtherClass (void (OtherClass::*fct)(), OtherClass*t) 
    :  f(fct),target(t) 
{
} 
void CommandOtherClass::execute() {
    (target->*f)();
}

SomeClass 函数可以修改如下:

class SomeClass {
public:
    static std::vector<unique_ptr<Command>> UpdateFuncs;
    static void executeAll();
};

请注意,您可以开发它以包含注册和取消注册功能,以便您还可以从涉及不再存在的对象的矢量命令中删除。

向向量中添加新命令的方法如下:

OtherClass::OtherClass() {
    SomeClass::UpdateFuncs.push_back(make_unique<CommandOtherClass>(&OtherClass::Update, this));
}

最后,这里是一个完整的online demo,它调用了两个自动为某些本地对象注册的命令,甚至添加了第三个与任何其他对象无关的临时命令。

【讨论】:

  • 虽然这是 100% 正确,但问题中显示的错误实际上是因为 &amp;(this-&gt;Update) 应该是 *OtherClass::Update
  • @Holt 是的,我已经编辑并添加了一些代码以使其更清晰
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-12
  • 2017-03-26
  • 1970-01-01
  • 2011-06-12
  • 2015-04-18
  • 1970-01-01
  • 2016-09-13
相关资源
最近更新 更多