c++ 在类内部分配函数指针

x759pob2  于 2023-05-30  发布在  其他
关注(0)|答案(2)|浏览(131)

我正在写一个简单的实验代码来测试将一个类的成员函数分配给另一个类的成员函数指针。我的示例代码无法编译。编译器显示错误:* '&':绑定成员函数表达式操作非法。*
我看到有些人在传递一个指向成员函数的指针时会这样做(&ClassB::printFun)。它对我不起作用,因为printFun不是一个静态成员函数。我也看到有人使用std::bind。但是std库对我来说不是一个选择,因为我将使用它来编写内核模式代码。我一直在寻找正确的方法来做到这一点有一段时间了,有人可以帮助我吗?谢谢!

using namespace std;

class ClassA
{
public:
    ClassA(void(*callBack)(int));
    void (*funPtr)(int);
};

ClassA::ClassA(void(*callBack)(int))
{
    funPtr = callBack;
}

class ClassB
{
public:
    void printFun(int a)
    {
        cout << a << endl;
    }
};

int main()
{
    ClassB classB;
    ClassA classA(&classB->printFun);
    classA.funPtr(5);
    return 0;
}
hi3rlvi2

hi3rlvi21#

指向函数的指针和指向成员函数的指针是不同的东西。你需要一个对象来调用成员函数。
一个指向meber函数的指针可以这样声明:

void (ClassB::*ptrPtrintFunc)(int) = &ClassB::printFun;

你可以这样称呼它:

ClassB classB;
(classB.*ptrPtrintFunc)(1);

或者这个:

ClassB *ptrClassB = &classB;
(ptrClassB->*ptrPtrintFunc)(2);

你能做的就是使用std::function代替老式的函数指针。你可以将一个lambda函数传递给std::function,在其中调用类的方法:

#include <iostream>
#include <functional>   // std::function

struct ClassA
{
    using TFunc = std::function<void( int )>; // <-- std::function<void( int )> insted of void(*)(int)
    ClassA( TFunc func) : funPtr( func ) {}
    TFunc funPtr;
};

struct ClassB
{
    void printFun( int a ) { std::cout << a << std::endl; }
};

int main()
{
    ClassB classB;
    ClassA classA( [&classB]( int a ) { classB.printFun(a); } ); // <-- lambda function
    classA.funPtr(5);
    return 0;
}

除了lambda函数,你也可以使用std::bindstd::placholder作为参数:

ClassB classB;
ClassA classA( std::bind( &ClassB::printFun, &classB, std::placeholders::_1 ) );
classA.funPtr(5);

当然,您也可以向std::function传递一个简单的函数

void printFunc( int a ) { std::cout << a << std::endl; }

ClassA classA( printFunc );

答案扩展:不使用STL的解决方案

谢谢你的信息。我使用std库打印的实验代码。但是我正在写的实际代码是在内核模式下,所以我将不能访问std库。我想知道是否有其他方法可以做到这一点。
如果你不想使用STL,你可以考虑使用抽象基类的解决方案。你需要一个带有抽象回调方法的基类,你需要两个覆盖抽象回调方法的派生类。回调方法的实现将回调委托给函数或类方法。
抽象方法CallBack的抽象类:

struct CCallBack
{
    virtual void CallBack( int ) = 0;
};

函数指针的实现。重写的方法CallBack将回调委托给函数指针:

struct CCallBackFunc : public CCallBack
{
    typedef void(*TFuncPtr)(int);
    TFuncPtr _funcPtr;
    CCallBackFunc( TFuncPtr funcPtr ) : _funcPtr( funcPtr ) {}
    virtual void CallBack( int a ) override { (*_funcPtr)( a ); }
};

方法函数指针的实现。被重写的方法CallBack将回调委托给一个对象和一个方法函数指针:

template < class T >
struct CCallBackMethod : public CCallBack
{
    typedef void(T::*TMethodPtr)(int);
    T &_obj;
    TMethodPtr _methodPtr;
    CCallBackMethod( T &obj, TMethodPtr methodePtr ) : _obj( obj ), _methodPtr( methodePtr ) {}
    virtual void CallBack( int a ) override { (_obj.*_methodPtr)( a ); }
};

两种情况的使用示例:

struct ClassA
{
    ClassA( CCallBack *cb ) : _cb( cb ) {}
    virtual ~ClassA() { delete _cb; }
    CCallBack *_cb;
};

struct ClassB { void printFun( int a ) { std::cout << a << std::endl; } };
void printFun( int a ) { std::cout << a << std::endl; }

int main()
{
    ClassB classB;
    ClassA classA0( new CCallBackFunc( &printFun ) );
    ClassA classA1( new CCallBackMethod<ClassB>( classB, &ClassB::printFun ) );
    classA0._cb->CallBack( 6 );
    classA1._cb->CallBack( 7 );
    return 0;
}
ldxq2e6h

ldxq2e6h2#

我还没有编译过,所以不确定它有多准确,但我会在现代编译器中努力实现类似这样的东西(C++17之前仍然):

#include <functional>

class A {
  public:
    A(std::function<void(int)> func)
        : func_( func )
    {}
    
    std::function<void(int)> func_;
}

class B {
  public:
    void printer(int val) { /* do something */ }
}

int main()
{
    B b{};
    A a([&](int val) { b.printer( val ); });

    a.func_(1);

    return 0;
}

相关问题