c++ - 如何将函数指针(我们不知道参数的函数)声明为类成员?

标签 c++ templates button pointer-to-member

我正在尝试实现一个按钮功能,我想过使用一些函数指针告诉程序如果按下按钮它必须调用什么函数。

问题是程序要调用的函数有各种参数和不同数量的参数(但函数总是返回 void),当然我不知道如何声明我的函数指针。

我该如何实现? 我应该使用一些模板吗? 我可以用模板做类似类型数组的事情吗,或者这是胡说八道吗?

这就是我实际的按钮类的样子:

#ifndef BUTTON_H_INCLUDED
#define BUTTON_H_INCLUDED

#include <SFML/Graphics.hpp>

#include <string>

class Button {
typedef unsigned short int usi_t;
public:
    Button();

    void updateState() {
        (isHover()) ? {
            m_currentBackgroundColor = m_backgroundColorIfHover;
            m_currentTextColor = m_textColorIfHover;
        } : {
            m_currentBackgroundColor = m_backgroundColorIfNothing;
            m_currentTextColor = m_textColorIfNothing;
        }
    }

private:
    /* State of the button */
    bool isHover() const {
        if (sf::Mouse.getPosition().x >= m_x && sf::Mouse.getPosition().x < m_x + m_w &&
            sf::Mouse.getPosition().x >= m_y && sf::Mouse.getPosition().y < m_y + m_h) {
                return true;
            }
        return false;
    }
    bool isClicked() const {
        if (isHover() && sf::Mouse.isButtonPressed(Left))
            return true;
        return false;
    }

    /* Function the button calls */
    void(*m_functionPtr)(/* What should I put here ? Should I use templates before the beginning of my class ? */);

    /* Position of the button */
    usi_t m_x;
    usi_t m_y;

    /* Dimension of the button */
    usi_t m_w; //weight
    usi_t m_h; //height

    /* Background color of the button */
    sf::Color m_currentBackgroundColor;
    sf::Color m_backgroundColorIfNothing;
    sf::Color m_backgroundColorIfHover;

    /* Text color of the button */
    sf::Color m_currentTextColor;
    sf::Color m_textColorIfNothing;
    sf::Color m_textColorIfHover;

    /* Border thickness and color */
    sf::Color m_borderColor;
    usi_t m_borderThickness;
    usi_t m_borderShadowThickness;

    /* Text of the button */
    std::string m_text;
};

#endif // BUTTON_H_INCLUDED

PS:事实上,我在吃东西的时候意识到我的问题在我的上下文中没有任何意义。我不会删除这个问题,假设它会对某人有所帮助。无论如何谢谢你。

最佳答案

How can I implement that ? Should I use some templates ? Can I do something like an array of type with templates, or is this non-sense ?

如果您使用的是 c++11,std::function 可以作为成员函数很好地工作(任何重载了 operator() 的类型 T 都可以绑定(bind)到它)。

为了您的客户,您可以通过使用函数模板来简化成员函数的绑定(bind):

另请注意,lambda 自动绑定(bind)到 std::function(与任何其他仿函数一样)。请参见下面的示例(使用绑定(bind)或 lambda):

#include <iostream>
#include <functional>

struct Button
{
    const std::string name_;
    std::function<void(const Button&)> function_;

    Button(std::string&& name)
    : name_(name)
    {
    }

    template <class Receiver>
    void setOnButtonClick_lambda(
      Receiver& receiver, void (Receiver::*memberfunction)(const Button&) )
    {
      auto* pReciever = &receiver; // can be done inside [] in C++14
      // create a lambda, store it in the std::function:
      function_ = [pReciever,memberfunction](const Button& b){
        (pReciever->*memberfunction)(b);
      };
    }

    template <class Receiver>
    void setOnButtonClick_bind(
      Receiver& receiver, void (Receiver::*memberfunction)(const Button&) )
    {
      function_ = std::bind(memberfunction, receiver, std::placeholders::_1);
    }

    void click()
    {
        (function_)(*this);
    }

};
struct Receiver
{
    void call(const Button& b){ std::cout << "Hallo from " << b.name_ << std::endl; }   
};

int main() 
{
    Receiver r;
    Button b1("b1 - bind");
    Button b2("b2 - lambda");

    b1.setOnButtonClick_bind(r, &Receiver::call);
    b2.setOnButtonClick_lambda(r, &Receiver::call);
    b1.click();
    b2.click();
    return 0;
}

或者如果你没有 c++11 的奢侈,你可以使用命令模式(下面的例子构建):

#include <iostream>

struct Cmd 
{
    virtual void execute() = 0;   
    virtual ~Cmd(){} 
};

struct Button
{
  private: 
    Cmd* onClick_;

    Button& operator=(Button);
    Button(const Button&);

  public:
      Button(): onClick_(){}
      ~Button()
      {
        delete onClick_;
      }

      void setOnClick(Cmd* onClick)
      {
        onClick_ = onClick;
      }

      void press()
      {
        if (onClick_){ onClick_->execute(); }
      }
};


 template <class Receiver> 
 struct Function : public Cmd
 {   
   typedef void(Receiver::*Callback)();

   Receiver& receiver_;   
   Callback call_;

   Function (Receiver& receiver, Callback call)   :
     receiver_(receiver),
     call_(call)   
   {   }   
   virtual void execute()   
   {
     (receiver_.*call_)(); 
   }
  };


struct Receiver
{
  Receiver()
  : btn_()
  {
    btn_.setOnClick(new Function<Receiver>(*this, &Receiver::call));
  }

  void testButtonPress()
  {
    btn_.press();
  }

  void call()
  {
    std::cout << "Pressed..." << std::endl;
  }

  Button btn_;  
};

int main() 
{
    Receiver receiver;
    receiver.testButtonPress();
    return 0;
}

我们的想法是,您接收 Cmd 作为按钮的基础,并执行命令,从而在不需要知道类型的情况下调用真正的函数。

... 或者使用像 boost 这样的库,它提供了 std::function ( see BoostLibs ) 的实现

关于c++ - 如何将函数指针(我们不知道参数的函数)声明为类成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31986372/

相关文章:

c++ - 什么是单元测试模板化 C++ 方法/类/函数的好方法?

qt - 如何使用 QGroupBox 代替 QButtonGroup

c++ - 如何实现一个在点击时执行不同功能的通用按钮类?

java - 我的代码中的 Jbutton 问题

c++ - 从接口(interface)转换为 QObject

c++ - 如何检索回滚驱动程序节点强名称?

templates - 相当于微格式的 DTD?

c++ - 模板二叉树的迭代器

c++ - 删除 [] 导致段错误?

c++ - CryptoAPI 和 XMLDSIG c、c++、delphi