c++回调函数我的理解,基础情况(调用非静态函数)

适用情况:

两个类之间回调。我直接时说最常用的。

基本知识(如果着急写可以不看):

1,两个类的头文件不能互相包含,所以你的全局常量的定义的位置必须得知道在这两个类的哪一个。
2,这个全局变量的定义type你得有点基本的理解。有时间还是要理解理解这个,这个可以提高你的能力。
3,回调肯定得回调静态的函数,重点是怎么由静态调用非静态。

开始正题:

两个类:被调用者Becaller;调用者Caller,(这个时候就得想一想了,起点在哪里,肯定是被调用者,Becaller->Caller,然后Caller在回调Becaller),这也是我为什么这么命名;

Becaller.h

#pragma once

#include <QWidget>
#include "ui_BeCaller.h"
using namespace std;
class Caller;
class BeCaller : public QWidget
{
	Q_OBJECT

public:
	BeCaller(QWidget *parent = Q_NULLPTR);
	~BeCaller();
	//被回调的函数必须是静态的
	static void callback(int a,int b,void *funcptr);
	void nonstatic(int a, int b);
	Caller *m_caller;
	
private:
	Ui::BeCaller ui;
};

Becaller.cpp

#include "BeCaller.h"
#include "Caller.h"
#include "qmessagebox.h"
BeCaller::BeCaller(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);
	//注册回调函数,也就是把要回调的函数传递过去,顺便把我这个指针也传递过去
	m_caller = new Caller;
	//传递过去的时候就把this也传递过去,到时候回调回来的时候得用到这个this
	m_caller->setwidgetcallback(callback,this);
}

BeCaller::~BeCaller()
{
}
//被回调的函数
void BeCaller::callback(int a, int b,void *callbackfun) 
{
//这里就是为什么要把this传递过去,又给传递回来,一切的开始在type的时候就准备好了
	BeCaller* becaller = (BeCaller*)callbackfun;
	becaller->nonstatic(a,b);
}
//你写的非静态的函数
void BeCaller::nonstatic(int a, int b) 
{
	QMessageBox::information(0, "", QString::number(a + b));
}

Caller.h

#pragma once
#include <QWidget>
#include "ui_Caller.h"
typedef void(*pf_w)(int , int ,void *func);//重点就在种了,知道为什么后面多加一个func指针。就是为了接受对象,到时候好用来调用非静态的函数
class Caller : public QWidget
{
	Q_OBJECT

public:
	Caller(QWidget *parent = Q_NULLPTR);
	~Caller();
	void setwidgetcallback(pf_w fun,void *caller);

private:
	Ui::Caller ui;
	pf_w m_callbackfun;
};

Caller.cpp

#include "Caller.h"
Caller::Caller(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);
}

Caller::~Caller()
{
}
void Caller::setwidgetcallback(pf_w fun, void* caller) {
	m_callbackfun = fun;
	m_callbackfun(1,2,caller);
}

到此为止,一个一般常用的回调函数就ok了,当然这也是最基本的情况了,能力有限。
下面讲一讲type吧。回调函数的起步就是这里。

我觉得最有用的就两个用途:

用途1:为复杂的声明定义起一个新的简单的别名,理解复杂声明可用的“右左法则”: 从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。

替换变量名,并把type关键字加在语句的开头

int* (*aa)(int, char*);
//找到变量名,aa,替换变量名,并把type关键字加在语句的开头
typedef int*(*pfunc)(int, char*);
pfunc aa;//这样会提示重定义,说明替换成功了

int*(a[4])(int ,char);第一步:找变量名,a,先往右,发现[]是个数组,(这里有一个很绕的东西,指针数组还是数组指针,网上有很多讲解,我自己的理解就是缺少一个“的”,指针的数组,数组的指针,这么一下就明白了,指针的数组,那肯定是一个数组存放着很多指针,数组的指针,那肯定是一个数组的指针,剩下的就是写法上的区分了,指针数组:int *a[4]; 数组指针:int (p)[4],这里就是一个算数优先级的问题了,()属于一级,属于二级)再往右,发现了圆括号,立马往左,找到左括号,这是一个整体,再往右,又发现了一个左括号,,立马往左,也是个刚才的括号,说明刚才那个整体是个函数,这个括号里面是参数,,继续往右,发现参数是int,char,又发现了圆括号,立马往左,函数名前面肯定是返回值类型了,返回值类型是int类型;

找到变量名了,是a,那就用一个新的别名pfunc替代变量名a,这是一个数组变量,a[4]是一个整体,再把type加在语句的开头就行了,typedef int*(pfunc)(int,char)

这就算是完成了,那么就可以使用简化版了,pfunc a[4];效果和直接写int*(a[4])(int ,char);是一样的。
上面用到了typedef定义复杂数据结构的其中一种用法,定义函数指针。
函数指针一般用于回调函数,中断处理过程的声明,以及在面向对象程序设计中对事件处理过程的声明
typedef其他的用法:
定义结构体类型,这个就不举例子了
定义数组类型,与定义结构体类型相似,可以用typedef来定义数组类型,
typedef int IntArray[100]
IntArray array;//这个就相当于int array[100]

补充一下运算符优先级

同一优先级的运算符,运算次序由结合方向所决定。

口诀:
作用域解析 ::最牛逼
括号成员第一; (左到右) //括号运算符。。 成员运算符 .和 ->
全体单目第二; (右到左) //所有的单目运算符比如++、 --、 +(正)、 -(负) 、指针运算 、&
乘除余三,加减四; (左到右) //这个"余"是指取余运算即%
移位五,关系六; (左到右) //移位运算符:<< >> ,关系:> < >= <= 等
等于(与)不等排第七; (左到右) //即== 和!=
位与异或和位或,“三分天下"八九十; (左到右) //这几个都是位运算: 位与(&)异或(^)位或(|)
逻辑或跟与; 十二和十一; (左到右) //逻辑运算符:|| 和 &&,注意顺序:优先级(||) 底于 优先级(&&)
条件高于赋值, 十三,十四 (右到左) //三目运算符?:优先级排到13 位只比赋值运算符和”,"高
逗号运算级最低! 十五 (左到右) //逗号运算符优先级最低
a=b=c;优先级相同,但是赋值表达式具有向右结合的特性,所以说这个结构是a=(b=c),表达式b=c的值赋值给a。如果是向左结合的哪就顺序来就行了a
b/c;(ab)/c;
p++,这个都是第二,右结合性,从右到左,那就是先++后,应该解析成
(p++)而不是(*p)++

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值