一、普通的函数指针一旦函数被编译并载入计算机中执行,它就会占用一块内存,这块内存有一个地址,因此函数也有地址。 1. 定义一个函数指针示例代码如下:void (*funcPtr)();这个例子将funcPtr定义为一个指向函数的指针,这个函数没有参数,返回值为空。注:*funcPtr 两侧的括号是必须的,如果去掉括号, void *funcPtr(); // 这表示funcPtr是一个函数,它返回类型为 void* 由于直接定义一个函数指针显得冗长,我们可以使用typedef对其进行简化,如下:typedef
void (*FuncPtrType)();此时我们将FuncPtrType定义为了一个函数指针类型,接下来我们可以使用这个类型来定义变量:FuncPtrType funcPtr; // 这个funcPtr与void (funcPtr*)();中的含义是一样的。 许多C/C++的面试题都喜欢出一些关于指针的题目,比如:说出下列式子的含义,复制代码1 void * (*(*fp1)(int))[10];2 3 float (*(*fp2)(int, int, float))(int);4 5 typedef
double (*(*(*fp3)())[10])();6 fp3 a;7 8 int (*(*fp4)[10])(); 复制代码对于fp1:我们从里向外一点一点分析,首先(*fp1)(int),这说明fp1是一个函数指针,它有一个int类型的参数;然后我们来找这个函数指针类型的返回值,注意到*(*fp1)(int),所以我们可以断定它的返回值是一个指针,指针指向什么呢?我们可以看到最外层剩余的部分是void* [10],因此这个函数的返回值是一个指针,这个指针指向一个包含十个void*类型数据的数组。综上:fp1是一个函数指针,它所指向的函数有一个int类型的参数,并且这个函数的返回值是一个指针,这个指针指向一个包含10个void*元素的数组。对于fp2就不再赘述了。fp2是一个函数指针,它所指向的函数有三个参数,参数类型分别为int,int,float;它的返回值是一个函数指针,这个函数指针所指向的函数具有一个int类型的参数,且返回类型为float。对于fp3fp3被定义为一个函数指针类型,这种函数指针所指向的函数的参数为空;它的返回值是一个指针,这个指针指向一个包含10元素的函数指针数组,这些函数指针所指向的函数的参数为空,返回值为double。对于fp4fp4是一个指针,这个指针指向一个包含10元素的函数指针数组,这些函数指针所指向的函数的参数为空,返回值为int。
《C陷阱与缺陷》中以下面一个例子对函数指针进行了讲解,如下:(*(void(*)())0)();如果能明白上边几个例子的含义,那么这个简直就是小case啊!同学们,你们能说出它的含义么??? 2. 使用函数指针在使用函数指针之前,我们首先要弄明白什么是函数指针。先看一段代码:、复制代码 1 void func(){ 2 cout<<"hello.\n"; 3 } 4 5 typedef void (*FuncPtr)(); 6 7 int main(){ 8 func(); 9 (*func)(); //
输出:hello. 注意这一行10 11 FuncPtr fp = func;12 fp(); // 输出:hello.13 fp = &func;14 fp(); // 输出:hello.15 (*fp)(); // 输出:hello.16 }复制代码 当这段代码成功被执行的时候,我自己也有点迷糊了,产生这样一个疑问:函数名到底是什么东东?我最初的认识是函数名就是代表了一段代码。但是(*func)();这行代码却可以正确地运行,那函数名是一个函数指针?但是fp = &func;这一行代码也没有错啊,Oh,
My Dog.在《C陷阱与缺陷》中有这样一段描述:fp是一个函数指针,那么*fp就是该指针所指向的函数,所以(*fp)()就是调用该函数的方式。ANSI C标准允许程序员将上式简写为fp(),但是一定要记住这种写法只是一种简写形式。在表达式(*fp)()中,*fp两侧的括号非常重要,因为函数运算符()的优先级要高于单目运算符*。如果*fp没有括号,那么*fp实际上与*(fp())的含义完全一致,ANSI C把它写作*(*(fp)())的简写形式。根据以上的描述,我们似乎可以得到这样一个结论:1. func是一个函数指针2.
func()是(*func)()的一个简写形式3. &func是&(*func)的简写形式如果这样理解正确的话,那么上面那段代码就顺理成章了。 有一种使用函数指针的方式很常用,叫做表驱动编码(table-driven code),使用这种方法可以根据不同的状态码来选择执行不同的函数。如果你用过MFC的话,应该对那个MESSAGE_MAP印象深刻吧,它本质上也是使用了这种思想,根据不同的消息ID来选择消息处理函数。我们可以列出这种方式的一个框架,复制代码 1 typedef void (FuncPtr*)();//
这里就不要参数了 2 struct Msg{ 3 int ID; 4 FuncPtr func; 5 }; 6 7 FuncPtr func1, func2, func3; // 声明三个函数指针 8 // 对函数指针赋值 9 initialFuncPtr();10 11 Msg arrMsg[] = {1, func1, 2, func2, 3, func3, 0, NULL}; // 最后一个赋值为012 13 int ID = GetMsgID();14 for (int i=0; arrMsg[i].ID;
++i){15 if (ID == arrMsg[i].ID)16 arrMsg[i].func();17 }复制代码 二、成员函数的指针 先看如下代码:复制代码 1 class Object{ 2 public: 3 bool equals(const Object& obj){ return true; } 4 }; 5 6 int main(){ 7 bool (Object::*equalsPointer)(const Object &); // 定义一个成员函数指针 8 equalsPointer
= &Object::equals; // 为equalsPointer进行赋值 9 Object obj;10 cout << boolalpha << (obj.*equalsPointer)(obj) << endl;11 } 复制代码第7行:bool (Object::*equalsPointer)(const Object &);这一行定义了一个指向Object类成员函数的指针equalsPointer,这种函数的返回值类型为bool,并且有一个参数,参数类型为const Object &。其中:Object::*equalsPointer两边的括号是必须的,如果没有括号:bool
Object::*equalsPointer(const Object &);上边的表达式是一个无效的函数声明第8行:equalsPointer = &Object::equals;这一行为equalsPointer进行了赋值。将Object::equals的指针赋给了equalsPointer。其中:与普通函数指针不同的是,若想取成员函数的指针必须使用(&)取地址运算符。也就是说,如果写成如下形式:equalsPointer = Object::equals; // Error,取成员函数的地址必须使用&
第10行:(obj.*equalsPointer)(obj)这一行调用了equalsPointer所指向的成员函数。C++中有两个针对成员指针的操作符:1. 成员指针解引用操作符(.*)从对象或引用获取成员;2. 成员指针箭头操作符(->*)从对象的指针获取成员。上边的例子中使用了(.*)操作符,(obj.*equalsPointer)(obj)其中,obj.*equalsPointer两边的括号是必须地,如果去掉括号:obj.*equalsPointer(obj) // 相当于:obj.*(equalsPointer(obj)),这会有编译错误在上边的表达式中,因为调用操作符”()”的优先级比成员指针操作符优先级高,所以不能去掉小括号。
函数指针
最新推荐文章于 2025-03-13 11:44:28 发布