【问题标题】:c++ pointer to non-static member functionsc++ 指向非静态成员函数的指针
【发布时间】:2018-01-02 01:45:52
【问题描述】:

我已经阅读了很多关于指向非静态成员函数的帖子和答案,但似乎没有一个能够解决我的问题。
所以我创建了一个简短的例子来复制我的问题:即使这个例子可以用不同的方式“解决”,对于最终的软件来说,保持例子中的结构很重要,谢谢。

这是“Funcs.h”类的头文件:

class Funcs
{
private:
  double a = 1, b = 2;

public:
  Funcs();
  ~Funcs();
  double Fun1(double X);
  double solver(double X0);
  double aaa(double(*fun)(double), double x0);
};

这是“Funcs.cpp”类的cpp:

#include "Funcs.h"

using namespace std;

Funcs::Funcs()
{
}

Funcs::~Funcs()
{
}

double Funcs::Fun1(double X) {
  double f1 = a*X;

  return f1;
}

double Funcs::solver(double X0)
{
  double result;

  result = aaa(Fun1, X0);
  return result;
}

double Funcs::aaa(double(*fun)(double), double x0)
{
  return fun(x0);
}

最后这是主要的“main.cpp”:

#include <iostream>
#include "Funcs.h"

using namespace std;

int main() {
  double x0=1;
  double result;
  Funcs funcs;

  result = funcs.solver(x0);
  cout << result << endl;

  return 0;
}

当我调用“result = aaa(Fun1, X0);”时,错误出现在 Funcs::solver 方法中因为我不能使用指向 Fun1 的指针,因为它是一个非静态成员。同时不能将其设为静态,否则在静态方法中看不到变量“a”。

提前感谢您的帮助。

【问题讨论】:

  • 那么你到底能改变什么?作为成员函数的某些东西与常规函数不同。
  • @NathanOliver ,对于我在其他帖子中看到的内容,我应该更改将第一个参数传递给函数“aaa(Fun1, X0);”的方式,这与编译器要求的相同,但我尝试过的一切都不起作用......
  • 您不能将成员函数指针转换为常规函数指针。您要么必须更改 aaa 接受的内容,要么将 Fun1 设为静态才能按原样使用 aaa

标签: c++ function-pointers non-static


【解决方案1】:

问题是您试图传递指向成员函数的指针,而需要指向非成员函数或静态成员函数的指针。这些是不同的类型。

这里的“fun”是一个指向函数的指针:double(*fun)(double)

这里是指向 Funcs 类的成员函数的指针:double(Funcs::*fun)(double)

以下是修改代码以使其工作的方法。

class Funcs
{
  // all the rest is the same
  double aaa(double(Funcs::*fun)(double), double x0);
};

double Funcs::solver(double X0)
{
  // ...
  result = aaa(&Funcs::Fun1, X0);
  // ...
}

double Funcs::aaa(double(Funcs::*fun)(double), double x0)
{
  return (this->*fun)(x0);
}

查看实时示例at Coliru

如果您想故意限制您的方法aaa 只接受Funcs 成员函数作为fun,这可能是一个不错的方法。如果您还想传递非成员函数或例如lambdas 到 aaa,考虑改用 std::function

【讨论】:

  • 感谢 Vasily,您的代码运行良好!唯一的“问题”是这样做,我应该为每个需要使用它的类实现一个成员函数aaa,因为在我的最终代码中将是一个通用的数学函数,可以用于很多事情。我可以,但有点浪费时间……你有避免这种情况的想法吗?
  • 我不完全确定我完全理解您的要求。让我澄清一下:你需要你的函数aaa 来接受几个类的成员函数,例如Foo::func1, 'Bar::func`。理解正确吗?
  • 如果是这样,那么您有几个选择,每个选项都假定您将aaa 移出班级。 1)您可以按照答案中的建议使用std::function - 请参阅example 1; 2) 你可以使用完美转发 - 见example 2; 3)如果您只想通过类的方法来限制参数,您仍然可以使用答案+模板提出的类似签名,请参阅example 3
  • 每种选择都有其优点和缺点,选择是你的;)
  • 谢谢,您已经完全理解了我的需求。我更喜欢第一个选项,但这只是因为看起来更容易一些。现在我添加了一个新函数 'bbb' 并调用了前一个 'aaa',但它会产生一个问题,因为参数再次是指向同一个函数的指针,但现在它不是从类中传递的。可以看看this code吗?
【解决方案2】:

您的问题是指向函数的指针与指向成员函数的指针不同。阅读this 了解更多信息,阅读this 了解编写指向成员函数的指针的简洁方式。如果您需要保留此结构,请将 aaa 设置为静态或非成员函数,它将所需的所有内容作为参数,或者将 aaa 的第一个参数更改为采用 double(Funcs::*)(double) 而不是 double(*fun)(double)。您甚至可以重载 aaa 以支持这两种用途。

【讨论】:

    【解决方案3】:

    其实Funcs::Fun1不是double(*)(double)

    任何非静态方法都有这个签名:return_type(*)(class_type* this, arguments...)

    让我们看看确切的类型:

    //first argument of `aaa` has type double(*)(double)
    double aaa(double(*fun)(double), double x0);
    
    double Funcs::Fun1(double X) {
      double f1 = a*X;
    
      return f1;
    }
    
    // Fun1 has type double(Funs::*)(double)
    // i.e it's a method of Funs and it takes (implicitly) first argument
    // which is `this` pointer
    
    // so that how `aaa` must  look like
    double aaa(double(Funs::*fun)(double), double x0)
    {
        // special sytax
        *this.*fun(x0);
    }
    
    // and that how `solver` looks like
    double Funcs::solver(double X0)
    {
      double result;
    
      // get pointer to method
      result = aaa(&Funs::Fun1, X0);
      return result;
    }
    

    如果您不熟悉指向方法的指针,请查看this

    【讨论】:

    • 您错过了 *this.*fun 周围的括号,即 (*this.*fun)(x0)。我很好奇你是如何在没有在真正的编译器中测试的情况下提交答案的。
    【解决方案4】:

    我还是 C++ 新手,但我知道的解决方案是让静态函数充当委托。 https://docs.microsoft.com/ru-ru/windows/win32/learnwin32/managing-application-state-

    ///关注完整代码的链接以了解我在说什么:)

    看看 win32 API 如何提供一个静态回调函数作为委托。简而言之,函数接受多个输入,最后一个参数是调用者作为 void 指针传递的类。

    static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
            DERIVED_TYPE *pThis = NULL;
    
            if (uMsg == WM_NCCREATE)
            {
                // routine to recast back pointer to your class type so you have access to your local members with "This"
                CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;  
                pThis = (DERIVED_TYPE*)pCreate->lpCreateParams;
                SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
    
                pThis->m_hwnd = hwnd;
            }
    

    看看 lParam 是如何被转换回 DERIVED_TYPE 的,这是你的类的一种类型,pThis 就像正常的 this 一样,让你可以访问类成员。

    【讨论】:

      猜你喜欢
      • 2010-11-02
      • 1970-01-01
      • 2020-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-21
      相关资源
      最近更新 更多