一个可以使用动态函数交换的函数

时间:2015-11-13 22:23:02

标签: c++

这听起来有点令人费解,但我们走了。

所以,我有以下代码:

  void Utility::validateRangeAndModify(Pet pet, int checkint, 
                                       int numbertovalidate, 
                                       bool greaterorless)
{
    if (greaterorless) {
        if (numbertovalidate < checkint)
            pet.getAttributes()->setPetHunger(0);
    } else
        if (numbertovalidate > checkint)
            pet.getAttributes()->func(100);
}

首先,此代码旨在验证单个整数。那部分很容易。

然后,我想要它做的是执行 a 函数,具体取决于整数是否满足条件。在这种情况下,setPetHunger()被设置为0或100.问题是,我也有setPetHealth()setPetEnergy()

我希望它执行的功能是我想要改变的事情。

例如。 此代码仅适用于我的宠物饥饿它不会起作用因为它的健康,幸福或任何其他变量。我还有很多其他的变数。

我想知道是否有办法实现这样的目标:

 void Utility::validateRangeAndModify(Pet pet, 
                                     int checkint, 
                                     int numbertovalidate, 
                                     bool greaterorless, 
                                     string functiontouse)
{

    if (greaterorless) {
        if (numbertovalidate < checkint)
            pet.getAttributes()->setPetHunger(0);
    } else
        if (numbertovalidate > checkint)
            pet.getAttributes()->FUNCTION_TO_USE(100);
}

我可以在C#中使用类似反射的东西。但是,我不知道c ++中的替代函数

3 个答案:

答案 0 :(得分:1)

您可以将正确的成员函数指针作为参数传递给Utility::validateRangeAndModify,如下所示:

void
Utility::validateRangeAndModify(Pet &pet, int checkint, int numbertovalidate, 
                                bool greaterorless, void(Attrib::*memfun)(int)) {
                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
  if(greaterorless) {
    if(numbertovalidate < checkint) (pet.getAttributes()->*memfun)(0);
  } else {
    if(numbertovalidate < checkint) (pet.getAttributes()->*memfun)(100);
  }
}

然后将其称为(如果Utility::validateRangeAndModify不是static使用obj.validateRangeAndModify):

Utility::validateRangeAndModify(p, 10, 9, false, &Attrib::setPetHunger);
Utility::validateRangeAndModify(p, 10, 9, false, &Attrib::setPetThirst);

LIVE DEMO

答案 1 :(得分:0)

您应该使用函数指针:

  void Utility::validateRangeAndModify(Pet pet, int checkint, 
                                       int numbertovalidate, 
                                       bool greaterorless,
                                       void (*func)(int, attribs &))
{
    if (greaterorless) {
        if (numbertovalidate < checkint)
            pet.getAttributes()->setPetHunger(0);
    } else
        if (numbertovalidate > checkint)
            func(100, pet.getAttribs());
}

您和客户将同意您将通过的功能原型;在这种情况下,原型将是void func(int, attribs &);

客户端可以编写如下代码:

void happiness(int level, attribs &a)
{
    // some code here
}
Utility::validateRangeAndModify(..., happiness);

现在happiness函数会调用validateRangeAndModify

注意:happiness是一个免费功能。如果它是成员函数,请将其标记为static:那么就不会有额外的this参数。

答案 2 :(得分:0)

为了简单起见,我提供了一个非常简单的程序,它使用std::bindstd::functionstd::placeholders来允许调用绑定方法。这样可以使用该方法保持正确的this,并且通常可以防止恶意。

#include <iostream>
#include <functional>

// bait class to catch bound function calls. Replace this with pet for OP's example
class TwoMethods
{
public:
    void method1(int val)
    {
        std::cout << "Method 1 received " << val << std::endl;
    }

    void method2(int val)
    {
        std::cout << "Method 2 received " << val << std::endl;
    }

};

// utility function that will operate on a bound function
void utilityfunction(std::function<void(int)> func)
{
    // calls passed function. Quietly handles bound this parameter and replaces 
    // placeholder with 42
    func(42);
}
int main()
{
    TwoMethods obj;

    // call utility function with appropriate object and method
    // the std::placeholders::_1 lets the compiler know there is another parameter that 
    // will be supplied later
    utilityfunction(std::bind(&TwoMethods::method1, obj, std::placeholders::_1));
    utilityfunction(std::bind(&TwoMethods::method2, obj, std::placeholders::_1));
}

在OP的案例中:

void Utility::validateRangeAndModify(int checkint, 
                                     int numbertovalidate, 
                                     bool greaterorless,
                                     std::function<void(int)> func)
{
    switch (greaterorless)
    {
        case 0: 
            {
                if (numbertovalidate < checkint) 
                { 
                    func(0); 
                }  
            } 
            break;
        case 1: 
            {
                if (numbertovalidate > checkint) 
                {
                    func(100); 
                } 
                break; 
            } 
    }
}

并称之为:

validateRangeAndModify(42, 666, false,
                       std::bind(&Attributes::setPetHunger,  
                                 pet.getAttributes(), 
                                 std::placeholders::_1))