回顾向 : 函数指针 & 回调函数 & 面向对象风格的C语言
面试的时候发现这个地方掌握的不够好,所以单独复习下,顺便写一篇博客。
这篇文章的所有代码都是用C实现的,这是由于C没有面向对象的特性,所以我希望用函数指针把C的结构体弄得有一点面向对象的感觉。
先介绍函数指针、回调函数,然后用C结合回调函数实现一个有面向对象风格的链表
函数指针:
函数指针,就是指向函数的指针
基本的函数指针(无参数无返回值)
//函数指针voidfun(){printf("fun()\n");}intmain(){//void*fp1()=&funvoid(*fp1)();fp1=fun;fp1();return0;}
有参数
//带参数voidfun(intval1,intval2){printf("val1=%d,val2=%d\n",val1,val2);}intmain(){void(*fp)(intval1,intval2)=&fun;fp(1,2);return0;}
有参数及返回值
//带参数及返回值intfun(intval1,intval2){returnval1+val2;}intmain(){int(*fp)(intval1,intval2)=&fun;intret=fp(1,2);printf("%d\n",ret);return0;}
但是,这样定义函数指针非常影响可读性,特别是对于复杂的函数,比如参数或者返回值也是函数指针类型的情况,因此,通常可以用typedef 如下:
//typedeftypedefint(*FP)(intval1,intval2);intfun(intval1,intval2){returnval1+val2;}intmain(){FPfp1=&fun;intret=fp1(1,2);printf("%d\n",ret);return0;}
回调函数:
而回调函数的实现,则利用了函数指针
简单的说,回调函数是一个函数,它的参数是函数指针和该指针所指向函数的参数,作为原本执行函数和目标函数之间的中介
为什么要用回调函数呢?回调函数的优势在于它的灵活性
通常我们调用函数,是被编译器最终转化成汇编语言、二进制文件的,板上钉钉的事情,这是事先决定好的,是静态的
但回调函数就不一样了,回调函数接受的参数,只是一个未知的函数的地址,是只有在执行时才可知的,是动态的
验证的标准就是,对于回调函数,如果传入的参数不是函数的地址,而是其他某个变量的地址,编译仍能正确执行,只有在运行时才出错。
上述的“动态特性” 是不是很像 C++中发生继承时的动态绑定呢?
简单的应用:
这里不得不顺便说一下,C++的相同自定义类的不通对象中的成员方法是公用的,怎么测试呢,看下面的C++代码
classTest{public:int_val=20;void_Print(){std::cout<<"hello?""<<endl;}};intmain(){Test*pt=NULL;t1._Print();//能执行t1._val=0;//崩溃,因为t1并没有指向一个Test类型的实例,因此当然访问不到_val成员了}
执行上述的代码,会发现即使整个代码并没有 Test对象的实例化,但仍能正确地调用Test中的_Print方法,这时由于C++类中的成员方法是公用的,并且并不是存放在每个类的对象中的,这么做当然是为了节省空间,那么我们能不能稍微借助一下这样的设计思路,用C简单的实现一个C++的类呢?
下面我将给结构体struct中定义函数指针,看看效果:
voidfun(){printf("hello\n");}typedefstructST{void(*_pf)();}ST;voidSet(ST**st)//类似构造函数{*st=(ST*)malloc(sizeof(ST));(*st)->_pf=&fun;}intmain(){ST*s1=NULL;Set(&s1);//初始化,这里貌似没办法在内部访问了s1->_pf();//像不像C++呢return0;}
在这段代码中,类ST是一个函数指针,而main函数的前两行则可以认为是C++中的构造函数,它的作用是将结构指针进行赋值,我定义这个函数是由于C中的结构体中的变量不支持在结构体内初始化。
然后我就可以像C++调用成员函数的方法了。
当然,这并不是原汁原味的C++的实现方式,C++是通过静态绑定的方式,在编译时就确定函数的位置的,而我是用动态的方式实现的,我的结构体中需要声明若干函数指针。
OK,接下来再实现一个简单的链表
structLinkListNode;typedefvoid(*pPushBack)(structLinkListNode*This,intdata);structLinkListNode*BuyNode(data);typedefstructLinkListNode{int_val;structLinkListNode*_next;pPushBack_PushBack;}LinkListNode;voidPushBack(LinkListNode*This,intdata){if(This==NULL){This=BuyNode(data);}LinkListNode*NewNode=BuyNode(data);LinkListNode*cur=This;while(cur&&cur->_next!=NULL){cur=cur->_next;}cur->_next=NewNode;}LinkListNode*BuyNode(intdata){LinkListNode*NewNode=(LinkListNode*)malloc(sizeof(LinkListNode));NewNode->_val=data;NewNode->_next=NULL;NewNode->_PushBack=&PushBack;returnNewNode;}voidInit(structLinkListNode**This,intdata){(*This)=BuyNode(data);(*This)->_val=data;(*This)->_next=NULL;(*This)->_PushBack=&PushBack;}intmain(){LinkListNode*Node1=NULL;Init(&Node1,1);Node1->_PushBack(Node1,2);Node1->_PushBack(Node1,3);Node1->_PushBack(Node1,4);return0;}
(完)
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。