博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为何成员函数指针模板不能像函数指针模板一样有简单的声明方式呢
阅读量:5959 次
发布时间:2019-06-19

本文共 3487 字,大约阅读时间需要 11 分钟。

http://topic.csdn.net/u/20101021/10/af09d7fb-5ab3-403d-a364-a6f06f472968.html

比如成员函数模板必须是:

template<typename T, typename RT, typename P1>
void test(T t1, RT (T::*mem_fun)(P1) , P1 p);
而函数指针即能能是:
template<typename RT, typename P>
void test(RT (*func)(P) , P p);
又能是:
template<typename F, typename P>
void test (F fun, P p)
根据使用场景,可以选择简单的定义。

--------------------------------------------------

http://blog.sina.com.cn/s/blog_4a50d85b0100umqe.html

C语言的指针相当的灵活方便,但也相当容易出错。许多C语言初学者,甚至C语言老鸟都很容易栽倒在C语言的指针下。但不可否认的是,指针在C语言中的位置极其重要,也许可以偏激一点的来说:没有指针的C程序不是真正的C程序。

  然而C++的指针却常常给我一种束手束脚的感觉。C++比C语言有更严格的静态类型,更加强调类型安全,强调编译时检查。因此,对于C语言中最容易错 用的指针,更是不能放过:C++的指针被分成数据指针,数据成员指针,函数指针,成员函数指针,而且不能随便相互转换。而且这些指针的声明格式都不一样:

数据指针 T *
成员数据指针 T::*
函数指针 R (*)(...)
成员函数指针 R (T::*)(...)

还有一个更重要的区别是,指针所占的空间也不一样了。即使在32位系统中,所占的空间也有可能是4字节、8字节、12字节甚至16字节,这个依据平台及编译器,有很大的变化。

  尽管C++中仍然有万能指针void*,但它却属于被批斗的对象,而且再也不能“万能”了。它不能转换成成员指针。

  这样一来,C++的指针就变得很尴尬:我们需要一种指针能够指向同一类型的数据,不管这个数据是普通数据,还是成员数据;我们更需要一种指针能够指向同一类型的函数,不管这个函数是静态函数,还是成员函数。但是没有,至少从现在的C++标准中,还没有看到。

 
沐枫网志 
  自从有了类,我们开始按照 数据+操作 的方式来组织数据结构;自从有了模板,我们又开始把 数据 和 算法 分离,以便重用,实在够折腾人的。但不管怎么折腾,现在大多数函数都不再单身,都嫁给了类,进了围城。可是我们仍然需要能够自由调用这些成员函数。
  考虑一下windows下的定时调用。SetTimer函数的原型是这样的:

C++指针探讨 <wbr>(三) <wbr>成员函数指针
UINT_PTR SetTimer(
C++指针探讨 <wbr>(三) <wbr>成员函数指针    HWND hWnd,
C++指针探讨 <wbr>(三) <wbr>成员函数指针    UINT_PTR nIDEvent,
C++指针探讨 <wbr>(三) <wbr>成员函数指针    UINT uElapse,
C++指针探讨 <wbr>(三) <wbr>成员函数指针    TIMERPROC lpTimerFunc
C++指针探讨 <wbr>(三) <wbr>成员函数指针);
C++指针探讨 <wbr>(三) <wbr>成员函数指针

其中,参数就不解释了,这个函数估计大多数windows开发人员都知道。lpTimerFunc是个会被定时调用的函数指针。假如我们不通过 WM_TIMER消息来触发定时器,而是通过lpTimerFunc来定时工作,那么我们就只能使用普通函数或静态函数,而无论如何都不能使用成员函数, 哪怕通过静态函数转调也不行。

  再考虑一下线程的创建:

C++指针探讨 <wbr>(三) <wbr>成员函数指针
uintptr_t _beginthread( 
C++指针探讨 <wbr>(三) <wbr>成员函数指针   
void
*
start_address )( 
void
 
*
 ),
C++指针探讨 <wbr>(三) <wbr>成员函数指针   unsigned stack_size,
C++指针探讨 <wbr>(三) <wbr>成员函数指针   
void
 
*
arglist 
C++指针探讨 <wbr>(三) <wbr>成员函数指针);C++指针探讨 <wbr>(三) <wbr>成员函数指针

start_address仍然只支持普通函数。不过这回好了,它允许回调函数一个void*参数,它将会arglist作为参数来调用 start_address。于是,聪明的C++程序员,就利用arglist传递this指针,从而利用静态函数成功的调用到了成员函数了:

C++指针探讨 <wbr>(三) <wbr>成员函数指针
class
 mythread
C++指针探讨 <wbr>(三) <wbr>成员函数指针
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针  
public
:
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
static
 
void
 doit(
void
*
 pThis)
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针    ((mythread*)pThis)
->
doit();
C++指针探讨 <wbr>(三) <wbr>成员函数指针    }
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
void
 doit()
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针}
C++指针探讨 <wbr>(三) <wbr>成员函数指针}
;
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针main()
C++指针探讨 <wbr>(三) <wbr>成员函数指针
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针  C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针  mythread
*
 pmt 
=
 
new
 mythread;
C++指针探讨 <wbr>(三) <wbr>成员函数指针  _beginthread(
&
mythread::doit, 
0
, (void*)pmt);
C++指针探讨 <wbr>(三) <wbr>成员函数指针  C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针}

  但是显然,C++程序员肯定不会因此而满足。这里头有许多被C++批判的不安定因素。它使用了C++中被认为不安全的类型转换,不安全的void*指 针,等等等等。但这是系统为C语言留下的调用接口,这也就认了。那么假如,我们就在C++程序中如何来调用成员函数指针呢?

  如下例,我们打算对vector中的所有类调用其指定的成员函数:

C++指针探讨 <wbr>(三) <wbr>成员函数指针
#include 
<
vector
>
C++指针探讨 <wbr>(三) <wbr>成员函数指针#include 
<
algorithm
>
C++指针探讨 <wbr>(三) <wbr>成员函数指针#include 
<
functional
>
C++指针探讨 <wbr>(三) <wbr>成员函数指针#include 
<
iostream
>
C++指针探讨 <wbr>(三) <wbr>成员函数指针
using
 
namespace
 std;
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针
class
 A
C++指针探讨 <wbr>(三) <wbr>成员函数指针
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
int
 value;
C++指针探讨 <wbr>(三) <wbr>成员函数指针
public
:
C++指针探讨 <wbr>(三) <wbr>成员函数指针    A(
int
 v)
{value 
=
 v;}
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
void
 doit()
{ cout 
<<
 value 
<<
 endl;}
;
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
static
 
void
 call_doit(A
&
 rThis)
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针        rThis.doit();
C++指针探讨 <wbr>(三) <wbr>成员函数指针    }
C++指针探讨 <wbr>(三) <wbr>成员函数指针}
;
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针
int
 main()
C++指针探讨 <wbr>(三) <wbr>成员函数指针
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针    vector
<
A
>
 va;
C++指针探讨 <wbr>(三) <wbr>成员函数指针    va.push_back(A(
1
));
C++指针探讨 <wbr>(三) <wbr>成员函数指针    va.push_back(A(
2
));
C++指针探讨 <wbr>(三) <wbr>成员函数指针    va.push_back(A(
3
));
C++指针探讨 <wbr>(三) <wbr>成员函数指针    va.push_back(A(
4
));
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
//
方法1:
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
//
for_each(va.begin(), va.end(), &A::doit); 
//
error
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
//
方法2:
C++指针探讨 <wbr>(三) <wbr>成员函数指针
    for_each(va.begin(), va.end(), 
&
A::call_doit);
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
//
方法3:
C++指针探讨 <wbr>(三) <wbr>成员函数指针
    for_each(va.begin(), va.end(), mem_fun_ref
<
void
, A
>
(
&
A::doit));
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针    system(
"
Pause
"
);
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
return
 
0
;
C++指针探讨 <wbr>(三) <wbr>成员函数指针}
C++指针探讨 <wbr>(三) <wbr>成员函数指针

  方法1,编译不能通过。for_each只允许具有一个参数的函数指针或函数对象,哪怕A::doit默认有一个this指针参数也不行。不是for_each没考虑到这一点,而是根本做不到!

  方法2,显然是受到了beginthread的启发,使用一个静态函数来转调用,哈哈成功了。但是不爽!这不是C++。
  方法3,呼,好不容易啊,终于用mem_fun_ref包装成功了成员函数指针。
  似乎方法3不错,又是类型安全的,又可以通用--慢着,首先,它很丑,哪有调用普通C函数指针那么漂亮啊(见方法2),用了一大串包装,又是尖括号又 是圆括号,还少不了&号!其次,它只能包装不超过一个参数的函数!尽管它在for_each中够用了,但是你要是想用在超过一个参数的场合,那只 有一句话:不可能的任务。

  是的,在标准C++中,这是不可能的任务。但事情并不总是悲观的,至少有许多第三方库提供了超越mem_fun的包装。如 boost::function等等。但是它也有限制:它所支持的参数仍然是有限的,只有十多个,尽管够你用的了;同样,它也是丑陋的,永远不要想它能够 简单的用&来搞定。

  也许,以失去美丽的代价,来换取质量上的保证,这也是C++对于函数指针的一种无奈吧……
  期待C++0x版本。它通过可变模板参数,能够让mem_fun的参数达到无限个……
--------
   BTW: C++Builder扩展了一个关键字 closure ,允许成员函数指针如同普通函数指针一样使用。也许C++0x能考虑一下……

-------------------------------------------------------

http://www.cnblogs.com/jans2002/archive/2006/10/13/528160.html

http://www.codeproject.com/KB/cpp/FastDelegate.aspx

你可能感兴趣的文章
安装EBS前期检查工具 - RDA - Health Check / Validation Engine Guide 2 结果
查看>>
Windows Phone笔记(11)使用独立存储(下)
查看>>
currentRowChanged 的注意事项
查看>>
面试题--在一个字符串中查找重复次数最多的字符(转)
查看>>
Beam内置的数据源清单(Java、Python)
查看>>
二维数组
查看>>
Ambari集群里操作时典型权限问题put: `/home/bigdata/1.txt': No such file or directory的解决方案(图文详解)...
查看>>
Objective-C:运行时runtime
查看>>
android 项目中出现红色感叹号的解决方法
查看>>
Android硬件加速
查看>>
SQL server 2005高可用性之----数据库镜像
查看>>
轻、快、好、免费的开发工具
查看>>
[LeetCode] Delete Duplicate Emails 删除重复邮箱
查看>>
fullCalendar动态获取数据
查看>>
Android 服务端开发之开发环境配置
查看>>
如何建立自己的私有云存储
查看>>
CPA,CPS,CPC,CPM的特点
查看>>
Phonegap Online和Offline
查看>>
软件设计
查看>>
代码生成工具Database2Sharp中增加视图的代码生成以及主从表界面生成功能
查看>>