引言
C++中成员函数在一般情况下是无法作为回调函数的 原因就是因为一般的成员函数在传参时为了可以访问成员变量或者返回本身 会默认的传一个 this 指针 但是回调函数再触发时会返回参数 这就会导致在把成员函数作为回调函数的时候会报参数错误这样一种奇怪的错误 那么如何去避免这种情况呢 本文针对此种情况介绍两种方法
一.类内静态成员函数作为回调函数
我们报错的原因是因为成员函数会隐式的传一个 this 指针,但静态成员函数就不会多这一个参数 所以我们的方法就是把类内静态成员当做回调函数 但这又牵扯到一个问题 就是这样做我们就无法访问自己的私有成员 那这样还有什么意义呢? 其实还有一种方法 就是设置一个静态的指针指向本身 用来访问其中的私有成员 切记静态成员要在类外赋值(const static可以使用初始化器在类内赋值), 一般来说设置一个指向自己的静态成员指针我们在类外初始化时赋予 nullptr 即可。但这样其实有不好的地方,就是破坏了类的封装性。
这是一个简单的消费者守护者模型代码 其中简单明了的显示的如何使类的成员函数作为回调函数
#include<iostream>
#include<queue>
#include<pthread.h>
#include<unistd.h>
using namespace std;
//类的成员函数作为线程函数使用
class cs
{
public:
static cs * pthis;
friend void * ddd(void *arg);
static void * customer(void *arg);//可以申请一个静态指针 把对象实体赋给指针 记的静态成员要初始化
static void * producer(void *arg);//原因是因为类外初始化可保证类内的等于号始终为赋值
cs();
cs& operator=(const cs &tmp) = default;
cs(const cs &tmp) = default;
~cs();
private:
queue<int>que;
void tempa(){cout << "消费者已消费!\n";}
void tempb(){cout << "生产者已生产!\n";}
pthread_mutex_t mux;
pthread_cond_t con;
pthread_t com_ptr;
pthread_t pro_ptr;
};
cs::~cs()
{
pthread_cond_broadcast(NULL);
pthread_join(com_ptr,NULL);
pthread_join(pro_ptr,NULL);
std::cout << "两个线程已销毁\n";
}
cs::cs():com_ptr(0),pro_ptr(0)
{
pthread_mutex_init(&mux,NULL);
pthread_cond_init(&con,NULL);
pthread_create(&com_ptr,NULL,pthis->producer,NULL);
pthread_create(&pro_ptr,NULL,pthis->customer,NULL);
}
void *ddd(void *arg)
{
while(1)
{
pthread_mutex_lock(&(pthis->mux));
pthis->que.push(1);
pthis->tempb();
pthread_cond_signal(&(pthis->con));
pthread_mutex_unlock(&(pthis->mux));
sleep(2);
}
}
void * cs::producer(void *arg)
{
while(1)
{
pthread_mutex_lock(&(pthis->mux));
pthis->que.push(1);
pthis->tempb();
pthread_cond_signal(&(pthis->con));
pthread_mutex_unlock(&(pthis->mux));
sleep(2);
}
}
void *cs::customer(void *arg)
{
cout << "消费者\n";
while(1)
{
pthread_mutex_lock(&(pthis->mux));
while(pthis->que.empty())
{
pthread_cond_wait(&(pthis->con),&(pthis->mux));
}
if(pthis->que.empty())
{
cerr << "模型出现错误!\n";
break; //这个函数只要退出就会发生错误
}
pthis->que.pop();
pthis->tempa();
pthread_mutex_unlock(&(pthis->mux));
}
}
cs * cs::pthis=nullptr; //静态成员必须初始化
int main()
{
cs tmp;
cs::pthis = &tmp; //把对象本身赋值给这个静态指针 //不足就是破坏了类的封装性
while(1)
sleep(30);
return 0;
}
二.显式强制类型转换
第一种方法虽然很完美的解决了我们的问题 但是它却有美中不足的地方 就是破坏了类的封装性,难道没有两全其美的方法了吗,答案当然是否定的,就是强制类型转换,这种方法不仅解决了我们的问题 而且保护了类的封装性 使得各个对象之间不互相影响 是一种很优秀的选择,这种方法可行的原因是因为 普通成员函数会使回调函数返回时产生参数错误 那我们就把成员函数转换为 void test(Test * )* 类型的函数 防止传递一个this指针,
#include<iostream>
#include<queue>
#include<pthread.h>
#include<unistd.h>
using namespace std;
class Test
{
private:
pthread_t pid;
int pri = 6;
void Fun(void *){
//默认参数为this 所以可以调用成员函数
cout << pri << " accept!\n";
}
public:
int StartPthread(){
typedef void* (*Temp)(void *);
Temp enp = (Temp)&Test::Fun;
pthread_create(&pid,nullptr,enp,this);
//参数为this 非常重要 否则会段错误
getchar();
}
};
int main()
{
Test tmp;
tmp.StartPthread();
return 0;
}