[C++基础]035_指针函数与函数指针<详细讲解>
1. 前言
关于指针函数和函数指针,特别是函数指针,相信很多C/C++ers跟我曾经一样,对它抱有敬畏,认为它是很高深的东西,其实不然。要理解它花不了多少功夫,或许我一句话就能说清楚二者的区别,但是这样也只是在脑子里形成一个概念而已。大学时代,作为一名学生时,我可以一天看完毛概,考八九十分;但是我用了一个星期去看谭浩强的C++教材(尽管现在很多人鄙视这本教材),上机时却仍无从下手,我可以侃侃而谈,熟悉一切概念,但是就是编不出程序。这就是程序员的世界,凡事只有动手才能领悟真谛。不过这也应证了一句千古名句,也是我最喜欢的一句诗“纸上得来终觉浅,绝知此事要躬行”。
本文所有代码编译及运行环境:windows 7 professionnal, Visual Studio2010 professional.
2. 概述
按照行文的总-分-总的结构,这里仍然先概括的介绍一下指针函数和函数指针的概念,然后再用程序来详细的介绍二者。下面就是指针函数和函数指针的概念。
【指针函数】:返回指针的函数。重点是它是一个函数,只是返回值由普通的值或对象变成了指针,也就是说这个函数返回的是一块内存的地址。
【函数指针】:指向函数的指针。重点是它是一个指针,只是它指向的内容由普通的变量或对象变成了函数,也就是说它可以指向函数的入口地址。
3. 指针函数
在介绍指针函数之前,我们先来看一个普通的函数。
1 #include <iostream> 2 using namespace std; 3 4 class MyType{ 5 public: 6 MyType(int value):m_value(value){ 7 cout<<"Construct."<<endl; 8 } 9 ~MyType(){ 10 cout<<"Desconstruct."<<endl; 11 } 12 public: 13 int m_value; 14 }; 15 16 MyType getInstanceOfMyType(){ 17 MyType mt(10); 18 cout<<&mt<<endl; 19 return mt; 20 } 21 22 int main(){ 23 24 MyType mt = getInstanceOfMyType(); 25 cout<<&mt<<endl; 26 cout<<mt.m_value<<endl; 27 28 system("pause"); 29 return 0; 30 }
涂色部分就是我们需要注意的地方,函数"getInstanceOfMyType()"内部创建了一个MyType的对象,接着输出了该对象的地址,最后返回了该对象。main函数里面,通过调用该函数,获得了函数的返回值,接着打印了返回对象的地址,再输出获得对象的m_value属性的值。输出结果如下:
Construct. 0045F688 Desconstruct. 0045F788 10 请按任意键继续. . .
可以看到,在"getInstanceOfMyType()"函数里,对象创建之后又被销毁了。从输出可以看出,返回的对象地址与函数里创建的对象地址是不一样的,但是属性m_value的值是一样的,这说明通过该普通函数获取的是函数内部创建对象的一个副本,这就是普通函数在返回对象时的处理。
在看到普通函数的处理之后,我们再来看一个指针函数的处理,下面是一段指针函数的代码,注意,这段代码与上一段很相似,要注意区分。
1 #include <iostream> 2 using namespace std; 3 4 class MyType{ 5 public: 6 MyType(int value):m_value(value){ 7 cout<<"Construct."<<endl; 8 } 9 ~MyType(){ 10 cout<<"Desconstruct."<<endl; 11 } 12 public: 13 int m_value; 14 }; 15 16 MyType *getInstanceOfMyType(){ 17 MyType *mt = new MyType(10); 18 cout<<mt<<endl; 19 return mt; 20 } 21 22 int main(){ 23 24 MyType *mt = getInstanceOfMyType(); 25 cout<<mt<<endl; 26 cout<<mt->m_value<<endl; 27 28 system("pause"); 29 return 0; 30 }
上面代码着色的部分需要我们注意,特别是函数"getInstanceOfMyType()",它在这里已经是一个指针函数了,那么,这段程序的输出是什么呢?如下:
Construct. 00754AA8 00754AA8 10 请按任意键继续. . .
可以看出,在函数"getInstanceOfMyType()"中的对象一直没有被调用析构函数,函数内和函数外的对象的地址是完全一样的,当然,对象里存储的内容m_value的值也是一样的。你可能会问,不是说函数调用完,就销毁局部变量吗?是的,它销毁了,但是它只销毁了"MyType *mt"这个指针,它指向的内存却不会被销毁。所以,在外面我们仍然可以继续访问这个对象。这种情况下,我们一般是需要在函数调用外面加上我们自己的delete操作的,上面的程序没有添加这样的操作,严格上来讲是一个错误的程序。
使用指针函数时,直接返回函数内部对象的地址,这样就无需重新制造对象的副本,对效率的提升有帮助。但是需要注意的是,一定要记得在函数外部将函数内部申请的内存释放掉,否则就有内存溢出的风险。
4. 函数指针
下面说道我们今天主要的话题了——函数指针。函数指针是一个很有用的技术,它使得我们可以通过指针就能执行某一个函数代码。对于技术高超的人来说,它是一把【绝世好剑】,能够解决很多问题。下面,我们就函数指针来探究一番。
首先,来看一段最简单的函数指针的代码,注意声明和调用的方式。
1 #include <iostream> 2 using namespace std; 3 4 int printFunc(int value){ 5 cout<<"this is a print function. the value is:"<<value<<endl; 6 return 0; 7 } 8 9 int main(){ 10 11 int (*pFunction)(int x); // 这是一个函数指针变量 12 pFunction = printFunc; // 这里将函数入口地址给函数指针 13 (*pFunction)(7); // 通过*运算符获取了函数,再传入参数7执行了函数 14 15 system("pause"); 16 return 0; 17 }
上述代码着色部分就是函数指针的声明-定义-执行的过程,可以看出来,我只要将函数入口地址给函数指针就可以执行函数了。这里有个知识点,就是关于函数的调用方式,一般我们调用函数的方式是这样的:函数名(参数列表),但是其实函数的调用方式也可以这样来写:(*函数名)(参数列表)。即可以如下来调用函数,只是很少这样用:
1 (*printFunc)(8);
除此之外,我们还可以这样写:(&函数名)(参数列表)。即如下调用函数,这也几乎没人这样用:
1 (&printFunc)(8);
对于函数指针,它有两个前提:①.就是指向的函数返回值要与声明的函数指针一致。②.指向的函数的参数类型及个数要与声明的函数指针一致。否则,是无法编译通过的。
5. 函数指针类型
上面一节在使用函数指针的时候,直接声明了一个函数指针。其实函数指针也可以借助typedef声明为一个类型,这样我们就可以像定义int型变量一样来定义一个函数指针了。定义函数指针类型代码如下:
1 #include <iostream> 2 using namespace std; 3 4 int printFunc(int value){ 5 cout<<"this is a print function. the value is:"<<value<<endl; 6 return 0; 7 } 8 typedef int (*PFunction)(int x); // 函数指针类型,注意返回值和参数列表 9 10 int main(){ 11 12 PFunction ptrFunc; // 定义函数指针变量 13 ptrFunc = printFunc; 14 (*ptrFunc)(1); // 第一种调用方式 15 ptrFunc(2); // 第二种调用方式 16 17 system("pause"); 18 return 0; 19 }
6. 一个函数指针的妙用示例
1 #include <iostream> 2 using namespace std; 3 4 typedef void (*PFunction)(int x); // 函数指针类型,注意返回值和参数列表 5 6 void printA(int value){ 7 cout<<"A - "<<value<<endl; 8 } 9 10 void printB(int value){ 11 cout<<"B - "<<value<<endl; 12 } 13 14 void printC(int value){ 15 cout<<"C - "<<value<<endl; 16 } 17 18 int main(){ 19 int choice; 20 PFunction ptrFunc[3] = {printA, printB, printC}; 21 cin>>choice; 22 ptrFunc[choice](choice); 23 24 system("pause"); 25 return 0; 26 }
具体的这里就不解说了,代码很短,也很容易看懂。
7. 结语
本文就指针函数和函数指针做了一个简单的入门讲解,希望读者在阅读完本文以后,对指针函数和函数指针有一个深入的认识。当然,写作本文的目的也是为了强化笔者的C++基础功底。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库