今天在练习代码,在使用成员函数指针作为参数时遇到了一些问题,记录一下。因为成员函数指针不像c里的普通函数指针,成员函数是包含了this指针的,用this指针去访问了对象的数据,所以成员函数的调用是需要对象的(如果定义成static,那跟c里的普通函数差不多了)。c++里成员函数指针的调用有三种运算符(->*, ::*, .*)。
使用场景:在一个类的成员函数里注册另外一个类的成员函数,在这个类里调用成员函数指针。
//server.h
#ifndef __SERVER_DEF_H__
#define __SERVER_DEF_H__
#include <stdint.h>
#include <string>
#include "session.h"
class CServer
{
public:
CServer(/* args */);
~CServer();
void start(CSession *session);
private:
// 回调函数
void onEvent(int32_t fd, std::string msg);
};
#endif
//server.cpp
#include <memory>
#include <stdio.h>
#include "server.h"
#include "session.h"
CServer::CServer()
{
}
CServer::~CServer()
{
}
void CServer::start(CSession *session)
{
session->init(this, &CServer::onEvent);
}
void CServer::onEvent(int32_t fd, std::string msg)
{
printf("input event fd = %d, msg = %s\n", fd, msg.c_str());
}
在声明指定类的成员函数指针时,用到了前置声明,不需要包含其头文件,这里也不能包含,因为在server.h里包含了session.h,因为成员函数指针调用必须用对象,所以这里同时也声明了一个CServer的指针。
//session.h
#ifndef __SESSION_DEF_H__
#define __SESSION_DEF_H__
#include <stdint.h>
#include <string>
//前置声明,声明一个类的成员函数指针
class CServer;
typedef void (CServer::*funcProc)(int32_t fd, std::string msg);
class CSession
{
public:
CSession();
~CSession();
void init(CServer *server, funcProc proc);
void event();
private:
CServer *mServer;
funcProc mProc;
};
#endif
相同的类型是可以赋值的,所以mProc = proc没有问题,成员函数指针的调用这里用到了->*
//session.cpp
#include "session.h"
CSession::CSession(): mServer(nullptr), mProc(nullptr)
{
}
CSession::~CSession()
{
}
void CSession::init(CServer *server, funcProc proc)
{
mServer = server;
mProc = proc;
}
void CSession::event()
{
int32_t fd = 120;
std::string msg = "callback test";
if(mServer && mProc)
{
(mServer->*mProc)(fd, msg);
}
}
程序执行结果:
这里是最简单的成员函数指针用例,在公司级的项目上肯定不会这样用,用到的是模板,使用模板可以实现不同的参数类型,同时可以同时做到c类型的普通函数,和c++类的成员函数,还能实现"信号槽",可以实现注册多个观察者,当事件发生时所有注册的回调都会调用。