将在类中声明的函数作为参数传递会导致编译错误

时间:2019-01-02 09:49:50

标签: c++ function-pointers

我将函数指针作为参数传递时遇到了问题。

指向函数类型的指针的声明:

typedef void(*cbk_fct)(void);

Operation的构造函数接受cbk_fct作为参数,声明如下:

class Operation
{
 private:
 cbk_fct m_fct_ptr;

public:
 Operation(cbk_fct fct_ptr);
};

Operation::Operation(cbk_fct fct_ptr):
m_fct_ptr(fct_ptr)
{

}

现在类User将调用Operation的构造方法

class User
{
 public:
 User();
 void userOperation();
};

void User::userOperation()
{
 cout << "User operation"<<endl;
}

User::User()
{
 Operation op(userOperation); // This version doesnt work
}

此呼叫将产生以下错误:

no matching function for call to 'Operation::Operation(<unresolved overloaded function type>)'|
no known conversion for argument 1 from '<unresolved overloaded function type>' to 'cbk_fct {aka void (*)()}'

但是,如果我声明将函数作为参数传递给类之外,它将被接受

void UserOperationNotInClass()
{
 cout << "User operation"<<endl;
}

User::User()
{
 Operation op(UserOperationNotInClass); // This version works
}

很明显,错误消息提到它不能从''转换为'cbk_fct,但是这种类型的'未解析的重载函数类型'是从哪里来的

2 个答案:

答案 0 :(得分:1)

非静态成员函数与普通函数是同一件事。具体来说,它可以访问其对象this指针,这对于 normal 函数而言毫无意义。因此,编译器在说不存在从前者到后者的未知转换时是正确的。

答案 1 :(得分:0)

与自由函数不同,没有从成员函数到指向成员函数的指针的隐式转换,因此您永远无法提供userOperation。您必须使用&User::userOperation。在这方面,错误消息可能会更好。

已修复以下问题:&User::userOperation具有类型void (User::*)(void),与类型void (*)(void)(别名cbk_fct)不同。您总是需要一个User才能调用userOperation,而这无处可去。如果要使其包含成员函数,则必须更改Operation

(C兼容)C ++ 98的方式是在函数类型和void *的成员中都包含一个Operation,并传递this(或任何其他对象指针),隐式转换为void *

typedef void * context_ptr;
typedef void (* action_ptr)(context_ptr);

class Operation
{
 private:
 action_ptr m_action;
 context_ptr m_context;

public:
 Operation(action_ptr action, context_ptr context);
};

Operation::Operation(action_ptr action, context_ptr context):
m_action(action), m_context(context)
{}

class User
{
 static void callUserOperation(context_ptr);
 public:
 User();
 void userOperation();
};

void User::callUserOperation(context_ptr context)
{
    User * user = reinterpret_cast<User *>(context);
    user->userOperation();
}

void User::userOperation()
{
 cout << "User operation"<<endl;
}

User::User()
{
 Operation op(&User::callUserOperation, this);
}

在C ++ 11中,您可以使用std::function来保存具有特定签名的任何函数对象,并从捕获this并调用userOperation的lambda中构造它。

using action_ptr = std::function<void(void)>;

class Operation
{
 private:
 action_ptr m_action;

public:
 Operation(action_ptr action);
};

Operation::Operation(action_ptr action):
m_action(action)
{}

class User
{
 public:
 User();
 void userOperation();
};

void User::userOperation()
{
 cout << "User operation"<<endl;
}

User::User()
{
 Operation op([this]{ userOperation(); });
}