一、函数指针

函数存放在内存的代码区域内,它们同样有地址.如果我们有一个int test(int a)的函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。

1、函数指针的定义方式:data_types (*func_pointer)( data_types arg1, data_types arg2, ...,data_types argn);

例如: int (*fp)(int a); //这里就定义了一个指向函数(这个函数参数仅仅为一个int类型,函数返回值是int类型)的指针fp。

例子:

int test(int a)
{return a;
}
int main(int argc, const char * argv[])
{int (*fp)(int a);fp = test;cout<<fp(2)<<endl;return 0;
}

注意,函数指针所指向的函数一定要保持函数的返回值类型,函数参数个数,类型一致。

2、typedef定义可以简化函数指针的定义

例子:

int test(int a)
{return a;
}int main(int argc, const char * argv[])
{typedef int (*fp)(int a);fp f = test;cout<<f(2)<<endl;return 0;
}

3、 函数指针同样是可以作为参数传递给函数的

例子:

int test(int a)
{return a-1;
}
int test2(int (*fun)(int),int b)
{int c = fun(10)+b;return c;
}int main(int argc, const char * argv[])
{typedef int (*fp)(int a);fp f = test;cout<<test2(f, 1)<<endl; //调用test2的时候,把test函数的地址作为参数传递给了test2return 0;
}

运行,输出 : 10

4、利用函数指针,我们可以构成函数指针数组,更明确点的说法是构成指向函数的指针数组。

例子:

void t1(){cout<<"test1"<<endl;}
void t2(){cout<<"test2"<<endl;}
void t3(){cout<<"test3"<<endl;}int main(int argc, const char * argv[])
{typedef void (*fp)(void);fp b[] = {t1,t2,t3}; //b[] 为一个指向函数的指针数组b[0](); //利用指向函数的指针数组进行下标操作就可以进行函数的间接调用了return 0;
}

参考文章:http://blog.csdn.net/qingshuiyangfan/article/details/7692647

二、指向类成员函数的函数指针

定义:类成员函数指针(member function pointer),是C++语言的一类指针数据类型,用于存储一个指定类具有给定的形参列表与返回值类型的成员函数的访问信息。

基本上要注意的有两点:

①函数指针赋值要使用 &

②使用.*(实例对象)或者->*(实例对象指针)调用类成员函数指针所指向的函数

下面看两个例子:

A)类成员函数指针指向类中的非静态成员函数

对于nonstatic member function (非静态成员函数)取地址,获得该函数在内存中的实际地址

对于virtual function(虚函数),其地址在编译时期是未知的,所以对于virtual member function(虚成员函数)取其地址,所能获得的只是一个索引值

例子:

//指向类成员函数的函数指针
#include <iostream>
#include <cstdio>
using namespace std;class A
{public:A(int aa = 0):a(aa){}~A(){}void setA(int aa = 1){a = aa;}virtual void print(){cout << "A: " << a << endl;}virtual void printa(){cout << "A1: " << a << endl;}private:int a;
};class B:public A
{public:B():A(), b(0){}B(int aa, int bb):A(aa), b(bb){}~B(){}virtual void print(){A::print();cout << "B: " << b << endl;}virtual void printa(){A::printa();cout << "B: " << b << endl;}private:int b;
};int main(void)
{A a;B b;void (A::*ptr)(int) = &A::setA;A* pa = &a;//对于非虚函数,返回其在内存的真实地址printf("A::set(): %p\n", &A::setA);//对于虚函数, 返回其在虚函数表的偏移位置printf("B::print(): %p\n", &A::print);printf("B::print(): %p\n", &A::printa);a.print();a.setA(10);a.print();a.setA(100);a.print();//对于指向类成员函数的函数指针,引用时必须传入一个类对象的this指针,所以必须由类实体调用(pa->*ptr)(1000);a.print();(a.*ptr)(10000);a.print();return 0;
}

运行结果:

A::set(): 0x8048a38
B::print(): 0x1
B::print(): 0x5
A: 0
A: 10
A: 100
A: 1000
A: 10000

B)类成员函数指针指向类中的静态成员函数

例子:

#include <iostream>
using namespace std;class A{
public://p1是一个指向非static成员函数的函数指针void (A::*p1)(void);//p2是一个指向static成员函数的函数指针void (*p2)(void);A(){/*对**指向非static成员函数的指针**和**指向static成员函数的指针**的变量的赋值方式是一样的,都是&ClassName::memberVariable形式**区别在于:**对p1只能用非static成员函数赋值**对p2只能用static成员函数赋值****再有,赋值时如果直接&memberVariable,则在VS中报“编译器错误 C2276”**参见:http://msdn.microsoft.com/zh-cn/library/850cstw1.aspx*/p1 =&A::funa; //函数指针赋值一定要使用 &p2 =&A::funb;//p1 =&A::funb;//error//p2 =&A::funa;//error//p1=&funa;//error,编译器错误 C2276//p2=&funb;//error,编译器错误 C2276}void funa(void){puts("A");}static void funb(void){puts("B");}
};int main()
{A a;//p是指向A中非static成员函数的函数指针void (A::*p)(void);(a.*a.p1)(); //打印 A//使用.*(实例对象)或者->*(实例对象指针)调用类成员函数指针所指向的函数p = a.p1;(a.*p)();//打印 AA *b = &a;(b->*p)(); //打印 A/*尽管a.p2本身是个非static变量,但是a.p2是指向static函数的函数指针,**所以下面这就话是错的!*/
//    p = a.p2;//errorvoid (*pp)(void);pp = &A::funb;pp(); //打印 Breturn 0;
}

总结:

类成员函数指针与普通函数指针不是一码事。前者要用.*与->*运算符来使用,而后者可以用*运算符(称为“解引用”dereference,或称“间址”indirection)。

普通函数指针实际上保存的是函数体的开始地址,因此也称“代码指针”,以区别于C/C++最常用的数据指针。

而类成员函数指针就不仅仅是类成员函数的内存起始地址,还需要能解决因为C++的多重继承、虚继承而带来的类实例地址的调整问题,所以类成员函数指针在调用的时候一定要传入类实例对象。

C++ 函数指针 类成员函数指针相关推荐

  1. 10.2 运算符重载函数作为类成员函数和友元函数

    Complex operator+(Complex &c2) { Complex c; c.real=real+c2.real; c.imag=imag+c2.imag; return c; ...

  2. 【C/C++学院】(8)全局函数和类成员函数转化/友元/操作符重载

    1.全局函数和类成员函数转化 全局函数和成员函数的相互转化:只需要修改一个指向本类的this指针: #include <iostream> using namespace std;clas ...

  3. C++运算符重载函数作为类成员函数和友元函数

    C++运算符重载函数作为类成员函数 1.1成员函数的重载运算符左侧是一个类对象,而且与运算符函数类型相同. 因为必须通过类的对象去调用该类的成员函数,而且只有运算符重载函数和返回值类型相同,运算结果才 ...

  4. c++ 线程函数(类成员函数作为线程函数使用)

    C++类成员函数使用时,都会隐式传递一个this指针给该函数,this指针指向该类的对象.函数体可以通过显示调用该指针或直接访问类内成员. 回调函数是通过指针调用的函数,最常使用的回调函数就是在创建线 ...

  5. C++成员变量指针和成员函数指针

    深度探索C++对象模型这本书还有提到C++类的成员变量指针和成员函数指针,虽然在实际开发中用的不多,但是还是需要理解下. 一:成员变量指针 1.1 非静态成员指针 类成员变量指针,实际上并不是真正意义 ...

  6. linux线程创建 类函数吗,linux多线程创建时使用类成员函数作为参数

    实际上所有线程都是用来处理C函数的,而不是C++类成员函数.标准库中提供一个API函数,这个函数以回调函数指针作为线程的执行代码并在单独的线程中调用回调函数.问题是在这样的线程库中不能创建执行对象成员 ...

  7. 关于使用类成员函数作为回调的方法

    为什么类成员函数不能直接做为回调函数? 因为windows中,回调函数都是显式使用CALLBACk修饰符修饰,也就是_stdcall参数传递方式._stdcall修饰的函数,参数从右至左依次压入堆栈, ...

  8. C++中 线程函数为静态函数 及 类成员函数作为回调函数(转载)

    C++中 线程函数为静态函数 及 类成员函数作为回调函数 线程函数为静态函数: 线程控制函数和是不是静态函数没关系,静态函数是在构造中分配的地址空间,只有在析构时才释放也就是全局的东西,不管线程是否运 ...

  9. C++ 笔记(16)— 类和对象(类定义、类实例对象定义、访问类成员、类成员函数、类 public/private/protected 成员、类对象引用和指针)

    1. 类的定义 类定义是以关键字 class 开头,后跟类的名称.并在它后面依次包含类名,一组放在 {} 内的成员属性和成员函数,以及结尾的分号. 类声明将类本身及其属性告诉编译器.类声明本身并不能改 ...

最新文章

  1. Linux 的无障碍设置如何操作?
  2. ros::spinOnce()机制 有点东西
  3. uva 610(割边)
  4. python rm 条件_删除文件 (rm)
  5. Android Java和JavaScript互调
  6. APP视觉稿该怎么切图和标注
  7. 计算机本地网络如何共享,本地网络共享怎么实现
  8. 升级bios_华硕B350PLUS升级BIOS更换AMD 3900X步骤
  9. libusb android pc,libusb
  10. java小数左右移_Java将小数位移至两倍
  11. 编写高质量java代码_编写高质量的Java代码
  12. flash 倒计时功能
  13. springboot+vue房屋租赁系统-求租合同系统java
  14. HuaWei ❀ IP源防护概述
  15. 如何在微信分享的网页中显示描述和图片
  16. ICC学习——LAB0A
  17. AI高效学习路径总结
  18. 绝佳表现电商各类促销活动插画素材|玩转大促购物节
  19. MySQL 5.7 基于 GTID 的主从复制实践
  20. 以太坊Go-ethereum源码分析之启动流程

热门文章

  1. EasyRecovery14最新个人版数据恢复工具
  2. Spring框架快速入门(Spring超全面讲解)
  3. html5 放风筝,萧山5个放风筝绝佳地
  4. 访问者模式 Visitor
  5. Linux面试相关知识点看着一文就够了
  6. win10/win11安装时提示:“我们无法创建新的分区,也找不到现有分区”的解决方法
  7. Latex排版[1]:输入矩阵(latex如何输入矩阵、对角阵、方程组)
  8. 拿到软考高级证书就是高级职称了吗?
  9. 基于C90标准的C语言开发工具
  10. 异常org.mockito.exceptions.verification.TooManyActualInvocations解决方案