在C++里说到函数指针,有很多人都是避而远之,更别说什么“递归函数指针”了。但是实际上有的东西越是神秘,其原理反而越简单,所以我这里就先卖一个关子,假装介绍一个“高深的技巧”一样做这个开场白了。
什么是“函数指针”呢?(别砸我!我想从头开始讲)比如我们定义了一个函数:
int f(char);
我们先不管它的实现,我们只知道它的申明,那么我们就可以定义一个函数指针fp来指向它:
FuncPtr fp = f;//或:fp = &f;老实说,这2种写法有什么不同,我也不知道
fp();//运行f函数
注意C++是强类型安全的,也就是说,如果fp不是和f同类型的话,是不能赋值的,即使它们占用的存储空间一样大,甚至都是32位的整数(在别的系统里可能不同)。比如:
void g(char);
fp = g;//Error:type mismatch!
那么fp是什么类型的呢?
typedef int (* FuncPtr)(char);
fp的类型是FuncPtr。我这里只是简单的介绍,为后面的讨论做铺垫。如果你对这些代码有什么不懂的,我建议你还是看看专门的C++入门书籍。
现在我开始介绍“递归函数指针”。想象一下,如果一个函数能返回自己的指针,那么这个函数应该怎样定义呢?
FuncPtr fp = f(/*whatever*/);//运行f函数,得到函数指针
fp = fp(/*whatever*/);//运行f函数,得到函数指针
fp = fp(/*whatever*/);//运行f函数,得到函数指针
//...and so on
我们现在是在C++里,不是在C或是汇编里,在那些语言里没有类型检查,只要是存储空间一样大,什么都可以相互等同。在C++里,我们享受了类型安全的优点,现在该修补它带来的一些“缺陷”来当作回报了。也许有人很快会在脑海里闪过一些代码,类似于:
typedef FuncPtr (* FuncPtr)(/*whatever*/);//对应的函数指针的定义
FuncPtr f(/*whatever*/)//一个函数的定义
{
//do something...
return f;//返回函数的指针
}
这段代码显然是有问题的,原因不用我说,那么该怎么解决这个问题呢?我们把目光集中到了临时变量上。对于return by value(没找到合适的汉语对应)的C++函数,其返回值都是靠临时变量来传送的。比如一个函数function:
TypeA function()//return type is TypeA
{
TypeA a;
return a;//value type is TypeA
}
编译器会产生这样的等同代码:
void function(TypeA _tmp_)
{
TypeA a;
_tmp_ = a;//these are for "return a;"
return;
}
注意到函数的返回类型(_tmp_的类型)和a的类型是一样的,都是TypeA。那么能不能使_tmp_和a的类型不同呢?当然可以了!只要a能转化成_tmp_,或说_tmp_能从a构建出来,比如:
class TypeA{};
class TypeB
{
TypeB(){}
TypeB(const TypeA &){}//construct B from A
};
从一个typeA类型的对象可以构建一个TypeB类型的对象,那么我们可以这样修改上面的函数:
TypeB function()
{
TypeA a;
return a;//construct B-object from a
}
我们讨论到这里,也许有人会想到我下一步要做什么了!对了,由于在函数申明中,函数返回的值类型不能是函数本身的指针类型——不能简单的递规typedef,这在前面的例子里大家都看到了——那么我们需要一个类型转化:从函数本身的指针类型转化成另一个类型,再在赋值的时候转化回来,就可以了。于是我们定义的了一个类:
class _FuncPtrClass
{
//something magic here...
};
_FuncPtr f(/*whatever*/)//函数f定义
{
//do something...
return f;
}
typedef _FuncPtrClass (* FuncPtr)(/*whatever*/);//函数指针类型FuncPtr定义
我们来看看_FuncPtrClass类应该具有哪些特点。首先,它要能从FuncPtr对象构建出来,并且要负责传递这个指针的值,所以它需要一个FuncPtr类型的成员变量,和一个定制的构造函数。注意,FuncPtr的定义是在_FuncPtrClass之后的,所以实际上在_FuncPtrClass内应该重新定义FuncPtr:
class _FuncPtrClass
{
public:
typedef _FuncPtrClass (* FuncPtrInClass)(/*whatever*/);//重新定义FuncPtr为FuncPtrInClass
_FuncPtrClass(FuncPtrInClass f):f_(f){}//定制的构造函数
private:
FuncPtrInClass f_;//FuncPtrInClass类型的成员变量
};
现在函数f的定义就是完全合法的了,并且可以成功的运行。不过,好像还缺点儿什么——怎么样得到临时变量_FuncPtrClass-object里的函数指针的值呢?是的,我们还缺一个转换的函数,这可以通过一个简单的operator做到:
class _FuncPtrClass
{
//...
public:
typedef _FuncPtrClass (* FuncPtrInClass)(/*whatever*/);
_FuncPtrClass(FuncPtrInClass f):f_(f){}
operator FuncPtrInClass(){return f_;}//从_FuncPtrClass到FuncPtrInClass转换的函数
private:
FuncPtrInClass f_;
};
这就是我们最终版本的_FuncPtrClass,配合上:
_FuncPtr f(/*whatever*/)
{
//do something...
return f;
}
typedef _FuncPtrClass (* FuncPtr)(/*whatever*/);
我们就能放心的运行以前的代码了:
FuncPtr fp = f(/*whatever*/);//运行f函数,得到函数指针
fp = fp(/*whatever*/);//运行f函数,得到函数指针
fp = fp(/*whatever*/);//运行f函数,得到函数指针
//...and so on
好了,大功告成!
也许有人会认为我这里讲的例子一点实际用处也没有,的确,我也这样认为。不过我并不认为这个技巧是没用的。任何人说某个东西一点用处也没有,都有点武断的嫌疑。我所阐述的并不是这样的一个例子,而是这样的一种技巧,我也是从别的书上看过来的,但是我并不认为那位作者是在讲一个毫无用处的例子。
相关推荐
递归(含代码执行过程解释) 函数指针(含代码执行过程解释) 两个最难的问题的详细讲解 甚至包括其中代码的执行过程的讲解
C/C++高级应用资源:easyx 图形窗口下用结构体指针、递归函数制作多级菜单。 递归结构体、递归函数经典应用。
0033 利用递归函数计算阶乘 12 0034 函数模板的应用 13 0035 使用指针数组 13 0036 函数指针数组的应用 13 0037 函数重载的注意事项 14 0038 使用typename关键字 14 1.4 引用 14 0039 使函数返回多个...
6.5.1 用函数指针变量调用函数 6.5.2 用指向函数的指针作函数参数 6.6 返回指针值的函数 6.7 指针数组和指向指针的指针 6.7.1 指针数组的概念 6.7.2 指向指针的指针 6.8 有关指针的数据类型和指针运算的小结 6.8.1 ...
17.1.11 函数指针的异常说明 598 17.2 命名空间 599 17.2.1 命名空间的定义 599 17.2.2 嵌套命名空间 603 17.2.3 未命名的命名空间 604 17.2.4 命名空间成员的使用 606 17.2.5 类、命名空间和作用域 609 17.2.6 重载...
8,指针、地址和动态存储器 9,引用变量 10,递归 11,预处理器 12,函数模板 13,程序组织结构 第二部分 使用类 14,C++类 15,构造函数和析构函数 16,转换 17,类对象数组 18,类成员 19,友元 20,类和堆 21,...
13.2 有返回值的递归函数 393 13.3 按递归方式思考问题 397 13.3.1 递归设计技术 397 13.3.2 二分查找 398 13.3.3 编码 400 13.3.4 检查递归的正确性 402 13.3.5 效率 402 第14章 继承 410 14.1 继承基础 ...
7.7.1 定义成员函数的函数体 7.7.2 在类外定义成员函数 7.7.3 编写Sales_item类的构造函数 7.7.4 类代码文件的组织 7.8 重载函数 7.8.1 重载与作用域 7.8.2 函数匹配与实参转换 7.8.3 重载确定的三个步骤 ...
详细描述和演示了定义C++语言的关键字、语法、函数、类和特征。其中第一部分全面讨论了C++的C子集;第二部分详细介绍了C++本身的特性,如类和对象、构造函数、析构函数和模板等;第三部分描述了标准函数库;第四部分...
8,指针、地址和动态存储器 9,引用变量 10,递归 11,预处理器 12,函数模板 13,程序组织结构 第二部分 使用类 14,C++类 15,构造函数和析构函数 16,转换 17,类对象数组 18,类成员 19,友元 20,类和堆 21,...
8,指针、地址和动态存储器 9,引用变量 10,递归 11,预处理器 12,函数模板 13,程序组织结构 第二部分 使用类 14,C++类 15,构造函数和析构函数 16,转换 17,类对象数组 18,类成员 19,友元 20,类和堆 21,...
C++ primer plus学习笔记之三,分为一下几个部分: 函数参数:介绍了函数的生命规则以及定义 数组函数:数组作为变量时的使用方法 指针和const:灵活运用指针...函数指针:函数的指针作为变量在某些项目中会减少工作量
6.5.1 用函数指针变量调用函数 6.5.2 用指向函数的指针作函数参数 6.6 返回指针值的函数 6.7 指针数组和指向指针的指针 6.7.1 指针数组的概念 6.7.2 指向指针的指针 6.8 有关指针的数据类型和指针运算的小结 6.8.1 ...
5.4 递归函数调用 5.5 C++/CLI编程 5.5.1 接受数量可变实参的函数 5.5.2 main()的实参 5.6 小结 5.7 练习 第6章 程序结构(2) 6.1 函数指针 6.1.1 声明函数指针 6.1.2 函数指针作为实参 6.1.3 函数指针的数组 6.2 ...
5.4 递归函数调用 5.5 C++/CLI编程 5.5.1 接受数量可变实参的函数 5.5.2 main()的实参 5.6 小结 5.7 练习 第6章 程序结构(2) 6.1 函数指针 6.1.1 声明函数指针 6.1.2 函数指针作为实参 6.1.3 函数指针的数组 6.2 ...
第1章 计算机和C++编程入门 第2章 C++基础知识 第3章 更多的控制流程 第4章 过程抽象和返回值的函数 第5章 所有子任务的函数 第6章 I/O流:对象和类入门 第7章 数组 第8章 字符串和向量 第9章 指针和动态数组 第10章...
5.4 递归函数调用 5.5 C++/CLI编程 5.5.1 接受数量可变实参的函数 5.5.2 main()的实参 5.6 小结 5.7 练习 第6章 程序结构(2) 6.1 函数指针 6.1.1 声明函数指针 6.1.2 函数指针作为实参 6.1.3 函数指针的数组 6.2 ...
- 第七节 函数指针 - 第八节 引用 - 第九节 Typedef - 第十节 程序举例 - 本章小结 - 课后习题 ◇ 第八章 结构与链表 - 课前索引 - 第一节 结构及使用 - 第二节 结构变量作为函数参数 - 第三节 结构数组...