函数指针、类成员函数指针学习
转自:https://www.runoob.com/w3cnote/cpp-func-pointer.html,写的非常好
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) // 和fp定义相同的一个函数,返回类型和参数列表都相同 { return a; } int main(int argc, const char * argv[]) { int (*fp)(int a); // 声明一个函数指针 fp = test; // 可以用函数指针指向该函数 cout<<fp(2)<<endl; // 调用函数指针,=调用test函数 // 通过typedef定义函数指针,在使用时直接使用该类型,更简洁 typedef int (*fp)(int a); fp f = test; cout<<f(2)<<endl; return 0; }
1.1 函数指针做参数
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 fp f = test; cout<<test2(f, 1)<<endl; // 调用 test2 的时候,把test函数的地址作为参数传递给了 test2 return 0; }
2.类成员函数指针
- 与普通函数的区别是,获取地址要加&符号;
- 当调用类是实例时,用.*;类是对象指针时,用->*调用。
2.1 非静态成员函数
//指向类成员函数的函数指针 #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; }; int main(void) { A a; void (A::*ptr)(int) = &A::setA; // 定义一个指向A类的非static的成员函数setA指针ptr A* pa = &a; // 对象指针 //对于非虚函数,返回其在内存的真实地址 printf("A::set(): %p\n", &A::setA); //对于虚函数, 返回其在虚函数表的偏移位置 printf("A::print(): %p\n", &A::print); printf("A::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; } //输出结果: -> % ./Demo A::set(): 0x104d7ae7c B::print(): 0x0 B::print(): 0x8 A: 0 A: 10 A: 100 A: 1000 A: 10000
2.2静态成员函数
#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成员函数赋值 */ 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 ,这里调用好复杂,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; }
//真的好复杂,搞这么复杂,有什么应用场景吗,