`
king_tt
  • 浏览: 2109618 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

C++基础]指针函数与函数指针<详细讲解>

 
阅读更多

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++基础功底。

分享到:
评论

相关推荐

    c++数组指针函数等关键内容讲解

    c++数组指针函数等关键内容讲解 c++数组指针函数等关键内容讲解 c++数组指针函数等关键内容讲解

    C++函数指针调用具体案例

    C++大学课本,函数指针调用具体使用案例详细讲解

    有关C/C++的函数指针概念课件仅供学习使用

    里面包含函数和指针概念的详细讲解,北大名师所做。希望能够对学C/C++的同学有所帮助。

    C++编程思想 pdf

    125&lt;br/&gt;7.1.3 集合 126&lt;br/&gt;7.1.4 与C语言的区别 126&lt;br/&gt;7.2 指针 127&lt;br/&gt;7.2.1 指向const的指针 127&lt;br/&gt;7.2.2 const指针 127&lt;br/&gt;7.2.3 赋值和类型检查 128&lt;br/&gt;7.3 函数参数和返回值 128&lt;br/&gt;7.3.1 传递const...

    C++基类指针和派生类指针之间的转换方法讲解

    函数隐藏是指派生类中函数与基类中的函数同名,但是这个函数在基类中并没有被定义为虚函数,这种情况就是函数的隐藏。 所谓隐藏是指使用常规的调用方法,派生类对象访问这个函数时,会优先访问派生类中的这个函数,...

    详细讲解C++回调函数的文档!

    详细讲解C++回调函数。对于很多初学者来说,往往觉得回调函数很神秘,很想知道回调函数的工作原理。本文将要解释什么是回调函数、它们有什么好处、为什么要使用它们等等问题,在开始之前,假设你已经熟知了函数指针...

    黄邦勇帅C++专题讲解

    C++指针与数组的混合运算(补充指针的内容) C++指针与动态分配内存new关键字专题 C++模板专题 C++名称空间与作用域专题 C++类中的各种成员,嵌套类,友元,this指针专题 C++继承,虚函数与多态性专题 C++宏,预处理器,...

    <<C++入门经典>>pdf文档和代码

    &lt;&lt;C++入门经典&gt;&gt;pdf文档和代码,初学者可以学习一下. C++在几乎所有的计算环境中都非常普及,而且可以用于几乎所有的应用程序。C++从C中继承了过程编程方式的高效性,并集成了面向对象编程的功能。C++ 在其标准库中...

    c++指针与递归的详细剖析

    递归(含代码执行过程解释) 函数指针(含代码执行过程解释) 两个最难的问题的详细讲解 甚至包括其中代码的执行过程的讲解

    C++智能指针shared-ptr讲解与使用.pdf

    C++智能指针shared_ptr讲解与使⽤ ⼿动管理的弊端 在简单的程序中,我们不⼤可能忘记释放 new 出来的指针,但是随着程序规模的增⼤,我们忘了 delete 的概率也随之增⼤。在 C++ 中 new 出来的指针,赋值意味着引⽤的...

    C++智能指针详解.pdf

    #include &lt;boost/shared_ptr.hpp&gt; class CBase: public boost::enable_shared_from_this&lt;CBase&gt; { public: virtual void f(){}//必须有个虚函数才能向上向下转换。 } typedef boost::shared_ptr&lt;CBase&gt; CBasePtr; ...

    C++ 指针讲义大全以及代码讲解

    2 / 2 C++ 指针讲义 目录 指针概述 指针的声明与初始化 指针与内存 指针与数组 指针与函数 指针与动态内存分配 指针与对象 指针与常量 指针的高级应用 常见问题与解决方案 总结

    详解C++中的指针、数组指针与函数指针

    本文从初学者的角度,深入浅出地讲解C++中的指针、数组指针与函数指针,对最常混淆的引用传递、值传递和指针传递做了区处,需要的朋友可以参考下

    华为C++中级训资料。ppt讲解类 接口 运算符重载 模板 word讲解 C++语言中级教材讲授C++语言的运用技术,包括:类、对象之间的关系、对象的存储与布局、运算符重载、智能指针、仿函数、泛型编程,C++模式设计基本思想。

    华为 C++ 培训资料 经典 ...word讲解C++语言中级教材讲授C++语言的运用技术,包括:类、对象之间的关系、对象的存储与布局、运算符重载、智能指针、仿函数、泛型编程,C++模式设计基本思想。下载看吧

    C++11unique-ptr智能指针详解.pdf

    C++11unique_ptr智能指针详解 智能指针详解 在《》的基础上,本节继续讲解 C++11 标准提供的另⼀种智能指针,即 unique_ptr 智能指针。 作为智能指针的⼀种,unique_ptr 指针⾃然也具备"在适当时机⾃动释放堆内存...

    C++程序设计技能百练(code+exe)

    第1课讲解C++基础知识;第2课讲解数据类型和控制结构;第3课讲解函数;第4课讲解数组和指针;第5课讲解引用与结构;第6课讲解类和对象;第7课讲解堆、构造函数与拷贝构造函数;第8课讲解静态成员、友元与模板;第9课...

    C++指针介绍及使用说明

    通过本文的学习,读者不仅能够全面理解C++指针的基础知识,还能够掌握指针在实际编程中的应用技巧。文章不仅适合初学者入门学习,也能够帮助有一定基础的程序员深化对指针的理解,提高编程水平和代码质量。无论是...

    C++11unique-ptr智能指针详解(1).pdf

    C++11unique_ptr智能指针详解 智能指针详解 在《》的基础上,本节继续讲解 C++11 标准提供的另⼀种智能指针,即 unique_ptr 智能指针。 作为智能指针的⼀种,unique_ptr 指针⾃然也具备"在适当时机⾃动释放堆内存...

    C++高级参考手册 完全自学 内容详细 讲解通俗易懂

    第5章 函数重载与缺省参数 5.1 范围分解 5.1.1 用返回值重载 5.1.2 安全类型连接 5.2 重载的例子 5.3 缺省参数 5.4 小结 5.5 练习 第6章 输入输出流介绍 6.1 为什么要用输入输出流 6.2 解决输入输出流问题...

    新手学习C++入门资料

    主体:(一)&lt;C++与C语言的区别&gt; 一、C++概述 (一) 发展历史 1980年,Bjarne Stroustrup博士开始着手创建一种模拟语言,能够具有面向对象的程序设计特色。在当时,面向对象编程还是一个比较新的理念,Stroustrup...

Global site tag (gtag.js) - Google Analytics