通过获取非静态成员的地址来形成指向成员函数的指针来理解错误?

问题描述 投票:0回答:2

我有一个问题,我不知道如何解决。

我正在使用一个库,通过传递对一些函数的引用来构造类的实例。

void func_on_enter() {...}
void func() {...}
void func_on_exit(){...}

State state_a(&func_on_enter, &func, &func_on_exit);

我正在编写一个包含此类实例的类,因此尝试过这样的事情:

class MyClass{
private:
  void func_on_enter() {...}
  void func() {...}
  void func_on_exit(){...}

  State _state_a;

public:
  MyClass() : _state_a(&func_on_enter, &func, &func_on_exit) {}
};

我得到错误“ISO C ++禁止使用非限定或带括号的非静态成员函数的地址来形成指向成员函数的指针。说'&MyClass :: _ func_on_enter'”(显然,对于其他两种方法也是如此)。编译器有助于提供我尝试过的解决方案。

然而,编译器然后提醒我,没有匹配函数来调用'State::State(void (MyClass::*)(), void (MyClass::*)(), (MyClass::*)())'并且它没有已知的从'void (MyClass::*)()''void(*)()'的转换。

我尝试阅读有关此错误的类似问题,但似乎无法找到我理解并可以在这种情况下提供帮助的解决方案。

我考虑过尝试向State添加一个重载构造函数,但考虑到我可以从任何其他类调用它,这对于逐个类的情况来说似乎很荒谬。

我还想了一段时间我可以将函数设置为静态(因为它们对于MyClass的所有实例都是相同的),但我很快就记得他们将无法使用MyClass的非静态成员变量。

是否有一种方法可以提供转换或以另一种方式为State构造函数提供指针?

我真的可以在这方面提供一些帮助,因为我对如何前进的想法非常困惑。任何帮助或提示将不胜感激!

c++ member-function-pointers
2个回答
2
投票

指向非静态成员函数的指针无法转换为普通函数指针。一个void (MyClass::*)()需要一个MyClass对象来操作。原始指针不能保持任何类型的状态,因此void(*)()无法存储有关哪个MyClass对象进行操作的信息。

幸运的是,标准库有一个专为此目的而设计的类模板:std::functionstd::function是原始函数指针的一个或多或少的替代品,但它可以容纳任何类型的可调用对象,它与给定的签名兼容。这意味着它可以保持回调到类的特定实例所需的状态:

class State {
private:
  std::function<void()> on_enter;
  std::function<void()> func;
  std::function<void()> on_exit;

public:
  State(std::function<void()> on_enter, std::function<void()> func, std::function<void()> on_exit)
    : on_enter{std::move(on_enter)},
      func{std::move(func)},
      on_exit{std::move(on_exit)}
  {}

  void do_something() {
    on_enter();
    // stuff
    func();
    // more stuff
    on_exit();
  }
};

class MyClass {
private:
  void func_on_enter() {}
  void func() {}
  void func_on_exit(){}

  State state_a;

public:
  MyClass()
    : state_a([this]() { func_on_enter(); },
              [this]() { func(); },
              [this]() { func_on_exit(); })
  {}
};

Live Demo

在这里,我没有直接将指针传递给你的成员函数,而是将它们包装在lambda中,捕获要回调的对象的this指针。现在State对象能够调用这些成员,并且他们知道要操作哪个MyClass实例。

但是要小心对象的生命周期。由于state_a持有指向MyClass实例的指针,因此您需要确保MyClass的复制/移动构造函数和赋值运算符做正确的事情。编译器提供的默认实现是不够的。


0
投票
void func_on_enter() {...}
void func() {...}
void func_on_exit(){...}

State state_a(&func_on_enter, &func, &func_on_exit);

为此,State的构造函数必须接受void(*)()类型的函数指针。

_state_a(&MyClass::func_on_enter, &MyClass::func, &MyClass::func_on_exit)

为此,State的构造函数必须接受void (MyClass::*)()类型的成员函数指针。成员函数指针不能转换为函数指针。

您可以更改State的构造函数以接受正确类型的指针。

© www.soinside.com 2019 - 2024. All rights reserved.