指向函数的指针(一)-程序员宅基地

技术标签: C/C++  fp  编程  class  fun  

之所以想写一篇函数指针的文章,源于函数指针在C/C++编程中使用的广泛性,而对于一些初级编程者来说对函数指针的使用或许有些迷惑,而一旦在适当的时候使用了函数指针,会使代码简洁有力。本篇介绍的是函数指针的基础部分,函数指针复杂的应用将在下一篇介绍。

一  指向普通函数的指针

先来看一个函数:

int Sum(int a, int b)
{
  return a + b;
}

这个函数,调用方式可以如

Sum(1, 2);

若要表示函数的指针,可以用&Sum,也可以将Sum前边的地址操作符&去掉,对于普通函数,地址操作符&是可选的

下面介绍函数指针变量和函数指针类型: 

1.  函数指针变量

int (*FnName)(int, int);           // 声明一个函数指针,可以将FnName理解为新定义的变量
FnName = ∑			   // 将Sum函数的地址赋给它
(*FnName)(3, 5);		   // 和调用Sum(3, 5)的效果是一样的

第1行声明了一个函数指针变量,如果有疑问,可以将FnName理解为一个新定义的变量。函数指针变量的声明格式:

返回类型*函数指针变量)(参数列表);

第2行将Sum函数指针赋给它,注意,只有两个函数指针参数类型,返回值类型完全相同才可以赋值,注意修饰符const,&等不同也会导致赋值失败。

第3行是调用,调用格式:

*函数指针变量)(实参列表); 

2.  函数指针类型

前面介绍了函数指针变量的声明,那么函数指针类型如何声明呢?

在函数指针声明前面加个typedef就成了函数指针类型定义。
typedef int (*FnType)(int, int);   // 声明一个函数指针类型
FnType fb = ∑				    // 定义一个FnType类型的变量,并赋值
(*fb)(3, 5);					    // 函数调用

第1行声明函数指针的类型,FnType便是新声明的类型,它是函数指针的类型

第2行定义一个FnType类型的变量,并将Sum函数地址赋值给它。

第3行是函数调用。 

前面已经了解了函数指针的变量和类型,看下面的代码加深下理解:

int Sum(int a, int b)
{
  return a + b;
}

typedef int (*FnType)(int, int);
int Fun1(FnType ft, int x, int y)
{
  return (*ft)(x, y);
}
// 函数指针可以定义在参数列表中,在函数体内使用
int Fun2(int (*fn)(int, int), int x, int y)
{
  return (*fn)(x, y);  
}

int main()
{
  cout << Fun1(&Sum, 2, 3) << " ";  // 输出 5
  cout << Fun2(&Sum, 3, 4) << "\n"; // 输出 7
  return 0;
}

关于普通函数指针的学习就到这里吧,简单吧:),下面就来学习类的成员函数的指针。 

二 指向类成员函数的指针

先看下面这个类:

class Num
{
public:
  Num(){n_ = 0;}
  void Inc(int n);
  void Dec(int n);
  static int Sub(int a, int b);
private:
  long n_;
};

这个类中有普通成员函数,也有静态成员函数,无论哪种函数,函数指针表示方式都是:

&类名::函数名

如Num类三个成员函数的指针分别是:

&Num::Inc;

&Num::Dec;

&Num:: Sub;

1.  指向普通成员函数的指针

 声明一个指向类成员函数的指针时需要用到::*符号,左边是类名,右边是成员函数指针名:

返回类型 类名::*成员函数指针(参数列表);

调用的时候要用到.*或->*,左边是类对象的引用或指针,右边是成员函数指针:

(对象名.* 成员函数指针)(实参);

(对象指针->* 成员函数指针)(实参); 

代码示例:

int main()
{
  Num obj;
  void (Num::*mf)(int);    // 声明指向成员函数的指针 mf
  mf = &Num::Inc;           // 赋值  
  (obj.*mf)(1);             // 调用

  // 成员函数的指针类型
  typedef void (Num::*mt)(int);
  mt fn = &Num::Dec;
  (obj.*fn)(2); 

  return 0;
}

注意上面,Sub静态成员函数,其指针声明跟非静态成员函数不一样,下面来看静态成员函数的指针。 

2. 指向静态函数的指针
int (*smf)(int a, int b); // 注意写法
smf = &Num::Sub;
cout << (*smf)(6, 7); 	   // 调用方式跟上一节讲的普通函数调用方式一样

可以看到,静态成员函数指针变量、类型声明与普通函数一致。 

3. 指向虚函数的指针

先上代码:

class Base{
public:
  virtual void F() const
  {
    cout << "I am the Base\n";
  }

  typedef void (Base::*FnPtr)() const;
};

class Derived : public Base{
public:
  virtual void F() const
  {
    cout << "I am the Derived\n";
  }
};

int main()
{
  Base::FnPtr fp = &Base::F;
  Base base;
(base.*fp)();
  Derived derived;
  (derived.*fp)();

  return 0;
}

输出结果:

I am theBase

I am theDerived 

可见,虚函数的指针调用结果跟直接调用虚函数效果一样,虚函数的指针指向的函数地址是对象动态绑定的函数地址。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hzyong_c/article/details/7464202

智能推荐

看这一篇就够了!-Ajax详解_ajax解析-程序员宅基地

文章浏览阅读10w+次,点赞1.5k次,收藏7.4k次。今天来聊一聊前后端交互的重要工具Ajax结合上次跟大家分享的前后端交互基础,如果还没有看过的童鞋,以下是传送门前后端交互详解AJAX- 到底什么是Ajax?ajax 全名 async javascript and XML是前后台交互的能⼒也就是我们`客户端给服务端发送消息的⼯具,以及接受响应的⼯具是⼀个 默认异步执⾏机制的功能AJAX分为同步(async = false..._ajax解析

浅谈“三层结构”原理与用意_三层 all-程序员宅基地

文章浏览阅读4.7k次。序在刚刚步入“多层结构”Web应用程序开发的时候,我阅读过几篇关于“asp.net三层结构开发”的文章。但其多半都是对PetShop3.0和Duwamish7的局部剖析或者是学习笔记。对“三层结构”通体分析的学术文章几乎没有。2005年2月11日,Bincess BBS彬月论坛开始试运行。不久之后,我写了一篇题目为《浅谈“三层结构”原理与用意》的文章。旧版文章以彬月论坛程序中的部分代码举例_三层 all

2017年寒假集训分组测试赛2 Ranklist_返回比赛列表 普及组1 - day02 寒假集训 题目列表 比赛成绩表 c. 繁衍 杜俊萱 #c.-程序员宅基地

文章浏览阅读401次。初级二十四点游戏Time Limit: 1000MS Memory Limit: 65536KBSubmit StatisticProblem Description受李老师的影响,他4岁的孩子明明也开始喜欢传统的二十四点游戏了。不过,李老师觉得孩子太小,传统的二十四点的游戏太难了。于是,他把游戏作了简化:给明明两张牌,只能用一次加法或一次乘法运算,看看明明能不能算_返回比赛列表 普及组1 - day02 寒假集训 题目列表 比赛成绩表 c. 繁衍 杜俊萱 #c.

PCB设计笔记_顶层铺铜颜色和线的颜色一样吗-程序员宅基地

文章浏览阅读283次。https://www.51zxw.net/show.aspx?id=53901&cid=5743-4 工作层面 layer_ 叠层管理 机械层:mechical1 top overlay bottom overlay 丝印层 日期 板子名称 top paste :涂焊锡膏用的 bottom solder 上绿油 keep ou..._顶层铺铜颜色和线的颜色一样吗

源码级分析app是如何被启动的_appdeathrecipient-程序员宅基地

文章浏览阅读3.6k次。前言一个app的程序是怎么启动的?入口在哪里?听说ActivityManagerServices很屌,Why?Activity生命周期到底是谁调用的?Application又是在哪里初始化的?onCreate又是如何被调用的?面试官常常会问:为什么主线程使用looper.loop不会卡死界面?等等..是不是一直有这样的疑问?很懵逼对不对 - - ,那我们就站在巨人的丁丁上来解决一下这些问题,如果文..._appdeathrecipient

Leetcode 414. 第三大的数 腾讯校招面试题(一次遍历,最大值,次大值,此次大值必须同时更新)_long_min ? a : c;-程序员宅基地

文章浏览阅读66次。class Solution {public: int thirdMax(vector<int>& nums) { long a = LONG_MIN, b = LONG_MIN, c = LONG_MIN; for (auto num : nums) { if (num > a) { c = b; b = a; ..._long_min ? a : c;

随便推点

精彩回顾:面试官:说说这段代码存在什么问题?-程序员宅基地

文章浏览阅读1k次。精彩回顾:面试官:说说这段代码存在什么问题?养成了定期更新简历的习惯,我不再像以前那么焦虑了更多惊喜,请长按二维码识别关注你若喜欢,别忘了帮忙点【在看】 ...

ConstrainLayout 基础教程3,Android开发前景怎么样_barrierallowsgonewidgets-程序员宅基地

文章浏览阅读143次。android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="16dp"android:text="@string/warehouse"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="par._barrierallowsgonewidgets

Qt QTreeView树形视图用法_qtreeview setdata-程序员宅基地

文章浏览阅读1.8k次。1,树形结构的item设置为选中QModelIndex rootIndex;QModelIndex robotsIndex;QModelIndex nonMobileIndex;rootIndex = treeView->model()->index(0, 0);//最顶层item的indexrobotsIndex = treeView->model()->ind..._qtreeview setdata

使用Air724UG模块拍摄照片并上传至云服务器_air724ug 4g摄像头-程序员宅基地

文章浏览阅读9.9k次,点赞10次,收藏73次。文章目录前言基础知识编写 TCP 客户端代码编写 TCP 服务端代码前言最近在做物联网的项目,有一个需求是要每隔一段时间要拍摄一张现场的图片并上传至云服务器保存。在查阅了很多资料后,发现这方面的资料是真的匮乏。同时,tb 上的摄像头产品也太高度集成了,很难进行二次开发。一次机缘巧合下,在逛 tb 的时候偶然发现一款产品,就是如下图所示 Air724UG 模块,自带 4G 通信模块和摄像头接口,而且成本也比较便宜,带通信卡和摄像头总价格不超过 80,简直就是完美符合我需求的天选产品。同时该系列产品的官方网_air724ug 4g摄像头

【JS 逆向百例】WebSocket 协议爬虫,智慧树扫码登录案例分析_智慧树登录页面 csdn-程序员宅基地

文章浏览阅读3.6k次,点赞4次,收藏13次。WebSocket 协议爬虫案例分享_智慧树登录页面 csdn

HDU 1272小希的迷宫 并查集_c - 小希的迷宫-程序员宅基地

文章浏览阅读489次。一、内容 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走。但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了房间A和B,那么既可以通过它从房间A走到房间B,也可以通过它从房间B走到房间A,为了提高难度,小希希望任意两个房间有且仅有一条路径可以相通(除非走了回头路)。小希现在把她的设计图给你,让你..._c - 小希的迷宫

推荐文章

热门文章

相关标签