1. 前言
关于指针函数和函数指针,特别是函数指针,相信很多C/C++ers跟我曾经一样,对它抱有敬畏,认为它是很高深的东西,其实不然。要理解它花不了多少功夫,或许我一句话就能说清楚二者的区别,但是这样也只是在脑子里形成一个概念而已。大学时代,作为一名学生时,我可以一天看完毛概,考八九十分;但是我用了一个星期去看谭浩强的C++教材(尽管现在很多人鄙视这本教材),上机时却仍无从下手,我可以侃侃而谈,熟悉一切概念,但是就是编不出程序。这就是程序员的世界,凡事只有动手才能领悟真谛。不过这也应证了一句千古名句,也是我最喜欢的一句诗“纸上得来终觉浅,绝知此事要躬行”。
本文所有代码编译及运行环境:windows 7 professionnal, Visual Studio2010 professional.
2. 概述
按照行文的总-分-总的结构,这里仍然先概括的介绍一下指针函数和函数指针的概念,然后再用程序来详细的介绍二者。下面就是指针函数和函数指针的概念。
【指针函数】:返回指针的函数。重点是它是一个函数,只是返回值由普通的值或对象变成了指针,也就是说这个函数返回的是一块内存的地址。
【函数指针】:指向函数的指针。重点是它是一个指针,只是它指向的内容由普通的变量或对象变成了函数,也就是说它可以指向函数的入口地址。
3. 指针函数
在介绍指针函数之前,我们先来看一个普通的函数。
1 #include2 using namespace std; 3 4 class MyType{ 5 public: 6 MyType(int value):m_value(value){ 7 cout<<"Construct."<
涂色部分就是我们需要注意的地方,函数"getInstanceOfMyType()"内部创建了一个MyType的对象,接着输出了该对象的地址,最后返回了该对象。main函数里面,通过调用该函数,获得了函数的返回值,接着打印了返回对象的地址,再输出获得对象的m_value属性的值。输出结果如下:
Construct.0045F688Desconstruct.0045F78810请按任意键继续. . .
可以看到,在"getInstanceOfMyType()"函数里,对象创建之后又被销毁了。从输出可以看出,返回的对象地址与函数里创建的对象地址是不一样的,但是属性m_value的值是一样的,这说明通过该普通函数获取的是函数内部创建对象的一个副本,这就是普通函数在返回对象时的处理。
在看到普通函数的处理之后,我们再来看一个指针函数的处理,下面是一段指针函数的代码,注意,这段代码与上一段很相似,要注意区分。
1 #include2 using namespace std; 3 4 class MyType{ 5 public: 6 MyType(int value):m_value(value){ 7 cout<<"Construct."< m_value<
上面代码着色的部分需要我们注意,特别是函数"getInstanceOfMyType()",它在这里已经是一个指针函数了,那么,这段程序的输出是什么呢?如下:
Construct.00754AA800754AA810请按任意键继续. . .
可以看出,在函数"getInstanceOfMyType()"中的对象一直没有被调用析构函数,函数内和函数外的对象的地址是完全一样的,当然,对象里存储的内容m_value的值也是一样的。你可能会问,不是说函数调用完,就销毁局部变量吗?是的,它销毁了,但是它只销毁了"MyType *mt"这个指针,它指向的内存却不会被销毁。所以,在外面我们仍然可以继续访问这个对象。这种情况下,我们一般是需要在函数调用外面加上我们自己的delete操作的,上面的程序没有添加这样的操作,严格上来讲是一个错误的程序。
使用指针函数时,直接返回函数内部对象的地址,这样就无需重新制造对象的副本,对效率的提升有帮助。但是需要注意的是,一定要记得在函数外部将函数内部申请的内存释放掉,否则就有内存溢出的风险。
4. 函数指针
下面说道我们今天主要的话题了——函数指针。函数指针是一个很有用的技术,它使得我们可以通过指针就能执行某一个函数代码。对于技术高超的人来说,它是一把【绝世好剑】,能够解决很多问题。下面,我们就函数指针来探究一番。
首先,来看一段最简单的函数指针的代码,注意声明和调用的方式。
1 #include2 using namespace std; 3 4 int printFunc(int value){ 5 cout<<"this is a print function. the value is:"< <
上述代码着色部分就是函数指针的声明-定义-执行的过程,可以看出来,我只要将函数入口地址给函数指针就可以执行函数了。这里有个知识点,就是关于函数的调用方式,一般我们调用函数的方式是这样的:函数名(参数列表),但是其实函数的调用方式也可以这样来写:(*函数名)(参数列表)。即可以如下来调用函数,只是很少这样用:
1 (*printFunc)(8);
除此之外,我们还可以这样写:(&函数名)(参数列表)。即如下调用函数,这也几乎没人这样用:
1 (&printFunc)(8);
对于函数指针,它有两个前提:①.就是指向的函数返回值要与声明的函数指针一致。②.指向的函数的参数类型及个数要与声明的函数指针一致。否则,是无法编译通过的。
5. 函数指针类型
上面一节在使用函数指针的时候,直接声明了一个函数指针。其实函数指针也可以借助typedef声明为一个类型,这样我们就可以像定义int型变量一样来定义一个函数指针了。定义函数指针类型代码如下:
1 #include2 using namespace std; 3 4 int printFunc(int value){ 5 cout<<"this is a print function. the value is:"< <
6. 一个函数指针的妙用示例
1 #include2 using namespace std; 3 4 typedef void (*PFunction)(int x); // 函数指针类型,注意返回值和参数列表 5 6 void printA(int value){ 7 cout<<"A - "< < >choice;22 ptrFunc[choice](choice);23 24 system("pause");25 return 0;26 }
具体的这里就不解说了,代码很短,也很容易看懂。
7. 结语
本文就指针函数和函数指针做了一个简单的入门讲解,希望读者在阅读完本文以后,对指针函数和函数指针有一个深入的认识。当然,写作本文的目的也是为了强化笔者的C++基础功底。