现在的位置: 首页 > 综合 > 正文

函数指针传递的两种环境(全局函数与类成员函数) C++获取类成员函数的指针

2013年06月08日 ⁄ 综合 ⁄ 共 5719字 ⁄ 字号 评论关闭
文章目录

 

转载请标明是引用于 http://blog.csdn.net/chenyujing1234 

欢迎大家提出意见,一起讨论!

 

最近在代码中看到指针的调用方式,有些疑问,于是在论坛上发了问题

http://topic.csdn.net/u/20120531/15/904ece4c-013a-4df4-8a7f-41cca854f3e0.html?seed=627050603&r=78731714#r_78731714

现在对这个问题做个总结。

 

1、  函数指针的传递的两种环境(类成员函数)

运行的结果是:

I am function_One_Instance
I am function_Second_Instance

 

 

下面是原代码:

// ================================类里的函数指针调用方法====================================
class CTestFun
{
public:
	//  测试函数
	void testFunction(void)
	{
		// 方法一的使用
		function_One_User(function_One_Instance);
		// 方法二的使用
	 	function_Second_User(&CTestFun::function_Second_Instance);
		
	}

protected:
	// ================================法一:====================================
	/*****************************************************************************
	总结:如果函数实例没有定义成static形式,那么:
	      (1)那么函数指针的声明得加类空间名字; 
		  (2)在函数实例使用者内部得用this->来引用到函数指针
		  (3)在函数实例使用者的参数处得使用 CTestFun:来引用函数实例。
	              
	*/
	// 函数类型定义
	// 下面两名等价于 typedef void (*PFunction_One)();
	typedef void function_One();
	typedef function_One *PFunction_One;
	// 函数实例
	static void function_One_Instance()
	{
		printf("I am function_One_Instance\n");
	}	
	// 函数使用者
	void function_One_User(PFunction_One function)
	{
		function();
	}


	// ================================法二:=====================================
	/*****************************************************************************
	总结:如果函数实例没有定义成static形式,那么:
	      (1)那么函数指针的声明得加类空间名字; 
		  (2)在函数实例使用者内部得用this->来引用到函数指针
		  (3)在函数实例使用者的参数处得使用 CTestFun:来引用函数实例。
	              
	*/
	// 函数类型定义
	// 定义一个原型为BOOL Fun(int a);的函数指针
	typedef BOOL (CTestFun::*function_Second)(int);
	// 函数实例	
	BOOL function_Second_Instance(int candidate)
	{
		printf("I am function_Second_Instance\n");
		return TRUE;
	}
	// 函数使用者
	BOOL function_Second_User(function_Second function)
	{
		// function其实是函数的指针
		// 这里的"*function"是指找到function在类中的函数地址。
		// 不是表明function是函数的指针的指针
		// 一句话,使用类成员函数指针必须有“->*”或“.*”的调用
		if ( (this->*function)(1) == TRUE )
			return FALSE;
		return TRUE;
	}
	
};



int main()
{
	CTestFun testFun;
	testFun.testFunction();
	system("pause");

	return 0;
}

 

对于上面列出的代码,我的问题是:
1、把
  if ( (this->*function)(1) == TRUE )
  改为
  if ( (/*this->*/*function)(1) == TRUE )
  就会报错:
  error C2171: “*”: “CTestFun::function_Second”类型的操作数非法
  error C2064: 项不会计算为接受 1 个参数的函数

2、
  若改为
  if ( (/*this->**/function)(1) == TRUE )
  就会报错:
  error C2064: 项不会计算为接受 1 个参数的函数
  这是为什么呢? 为什么一定要加this.

1、2两个问题是同一个问题。

答:

如果函数实例没有定义成static形式,那么:
     (1)那么函数指针的声明得加类空间名字,以此具有全局属性。
    (2)在函数实例使用者内部得用this->来引用到函数指针
    (3)在函数实例使用者的参数处得使用 CTestFun:来引用函数实例。

3、BOOL function_Second_User(function_Second function)
  中的形参是函数指针而已。
  而调用的时候为什么是
  function_Second_User(&CTestFun::function_Second_Instance); (加了& ,即函数的指针的指针)
4、 void function_One_User(PFunction_One function)
  中的形参是函数的指针的指针,
  而调用时为什么是
  function_One_User((PFunction_One)function_One_Instance);
  只是函数指针?
3、4 其实是同一个问题。

答:

 由于加了CTestFun::来引用类中的函数成员
 所以加上  &。一句话,这是类中的规定。

 1、1  获得类中的函数指针,然后使用此函数 

代码如下:

#include <stdio.h>
#include <windows.h>



typedef void (*PFunction_One)();

class AA
{
public:
	void func()
	{
		printf("I am in AA.func()\n");
	}
};




int main()
{
	AA aA;
	PFunction_One tempFun = aA.func;
	tempFun();
	system("pause");
	return 0;
}

编译后会出错:

1>c:\users\chenyj\desktop\test\main.cpp(23) : error C3867: “AA::func”: 函数调用缺少参数列表;请使用“&AA::func”创建指向成员的指针

修改为:

#include <stdio.h>
#include <windows.h>



typedef void (*PFunction_One)();

class AA
{
public:
	static void func()
	{
		printf("I am in AA.func()\n");
	}
};




int main()
{
	AA aA;
	PFunction_One tempFun = AA::func;
	tempFun();
	system("pause");
	return 0;
}

此时编译成功,且结果正常。

1、2   C++获取类成员函数的指针

参考: http://blog.csdn.net/wulibin136/article/details/6328992

C++ class中有三种成员函数,static,nonstatic,virtual
各种成员函数的指针各有区别,以下是一个完整的例子:
class A 
{
public:
	static void staticmember(){cout<<"static"<<endl;}   //static member
	void nonstatic(){cout<<"nonstatic"<<endl;}          //nonstatic member
	virtual void virtualmember(){cout<<"virtual"<<endl;};//virtual member
};

int _tmain(int argc, _TCHAR* argv[])
{
	A a;
	//static member,取得的是该函数在内存中的实际地址,而且因为static成员是全局的,所以不能用A::限定符
	void (*ptrstatic)() = &A::staticmember;      
	//nonstatic member 取得的是该函数在内存中的实际地址     
	void (A::*ptrnonstatic)() = &A::nonstatic;
	 //虚函数取得的是虚函数表中的偏移值,这样可以保证能过指针调用时同样的多态效果
	void (A::*ptrvirtual)() = &A::virtualmember;
	//函数指针的使用
	ptrstatic();
	(a.*ptrnonstatic)();
	(a.*ptrvirtual)();
}

 

 

 

 

 

2、  函数指针的传递的两种环境(全局函数)

// ================================全局时函数指针调用方法====================================
/*****************************************************************************
	总结:由于在全局的函数都默认是加了static的。          
	*/

// 定义一个原型为int Fun( int a );的函数指针
typedef int (*PTRFUN)(int aPara);
// pFun 为函数指针变量名
PTRFUN pFun;    
// pFun2也是函数指针变量名
int (*pFun2)(int a);   


// 定义回调函数
int CallBack(int a)
{
	printf("I am CallBack\n");
	return ++a;
}

// 定义回调者函数
void Caller( PTRFUN cb )
// void Caller( int (*cb) ( int ) )		// 也可这样申明
{
	int nPara = 1;
	int nRet = cb( nPara );
}

// 使用回调
void TestFunP()
{
	Caller(CallBack);					// 直接使用回调函数
	PTRFUN cb = CallBack;				// int (*cb) ( int ); cb = CallBack;
	int nRet1 = cb( 99 );				// nRet1 = 100;
}


// ================================函数指针的指针使用========================================
// 定义函数指针的指针
typedef int (**PTRPTRFUN)(int aPara);
// 函数指针的指针作为参数
void PtrCaller(PTRPTRFUN cb)
// void PtrCaller( PTRFUN* cb )			// 指针申明
// void PtrCaller( int (**cb) ( int ) )	// 原型申明
{
	int nRet = (*cb)(999);				// nRet = 1000;
}

// 使用函数指针的指针
void TestFunPP()
{
	PTRFUN cb = CallBack;
	PtrCaller( &cb );
}


// ================================函数指针数组的使用========================================
// 函数指针数组的定义
PTRFUN fArray[10];
// int (*fArray[10])(int);				// 原型定义

void TestFunPArray()
{
	for ( int i = 0; i < 10; i++ )
	{
		fArray[i] = CallBack;
		int nRet = fArray[i](i);		// nRet = i+1;
	}
	
}

// ================================函数指针与typedef========================================
// 形式一:
// 定义了一个指针变量pFun1
// 它是一个指向某种函数的指针
char (*pFun1)(int); 
// 定义一个函数。
// 函数的函数名实际上就是一个指针,函数名指向该函数的代码在内存中的首地址
char glFun(int a){ return 1;} 
void testF1() 
{ 
	pFun1 = glFun; 
	// 取pFun1所指向的地址的内容,当然就是取出了glFun()的内容
	(*pFun)(2); 
} 

// 形式二:typedef 返回类型(*新类型)(参数表)
// typedef char (*PTRFUN)(int); 
// PTRFUN pFun; 
// char glFun(int a){ return;} 
// void main() 
// { 
// 	pFun = glFun; 
// 	(*pFun)(2); 
// } 

 三、

1、

按以下的方法声明一个函数

VOID _stdcall (*process)(DWORD  openHandle,
							UINT   event,
							LPVOID pData,
							UINT32 dataLength,
							UINT32 totalLength,
							UINT32 dataFlags);

编译时会报错:

 : error C2059: 语法错误 : “(”
 : error C2238: 意外的标记位于“;”之前

改为下面就不会了

	VOID (_stdcall *process)(DWORD  openHandle,
							UINT   event,
							LPVOID pData,
							UINT32 dataLength,
							UINT32 totalLength,
							UINT32 dataFlags);

 

 

抱歉!评论已关闭.