一、函数指针
函数存放在内存的代码区域内,它们同样有地址.如果我们有一个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函数的地址作为参数传递给了test2 return 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/
二、指向类成员函数的函数指针
定义:类成员函数指针(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)();//打印 A A *b = &a; (b->*p)(); //打印 A /*尽管a.p2本身是个非static变量,但是a.p2是指向static函数的函数指针, **所以下面这就话是错的! */ // p = a.p2;//error void (*pp)(void); pp = &A::funb; pp(); //打印 B return 0; }
总结:
类成员函数指针与普通函数指针不是一码事。前者要用.*与->*运算符来使用,而后者可以用*
运算符(称为“解引用”dereference,或称“间址”indirection)。
普通函数指针实际上保存的是函数体的开始地址,因此也称“代码指针”,以区别于C/C++最常用的数据指针。
而类成员函数指针就不仅仅是类成员函数的内存起始地址,还需要能解决因为C++的多重继承、虚继承而带来的类实例地址的调整问题,所以类成员函数指针在调用的时候一定要传入类实例对象。
今天的文章
c++指向成员函数的指针_类的成员函数都有this指针吗分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/89758.html