1 问题引入
在使用函数模板时有如下定义
template<typename xClass, typename xReturn>
void StartThread(xClass* pThis, xReturn (xClass::* pfn)())
{
return;
}
在基于对话框的程序中使用该函数模板
BOOL CMyDlg::OnInitDialog()
{
StartThread<CMyDlg, DWORD>(this, ThreadAccept);
}
而ThreadAccept()函数是CMyDlg的成员函数,定义如下
DWORD CMyDlg::ThreadAccept()
{
return 0;
}
此时,编译报错信息为
“error C3867: CMyDlg::ThreadAccept函数缺少参数列表”。
2 问题分析
主要问题出在函数调用方式上。在CMyDlg::OnInitDialog()函数中,使用_cdecl的方式直接调用ThreadAccept();在函数模板中定义的StartThread()函数的第二个参数是xClass::*,表示类的成员函数的指针,而类成员函数的调用方法是__thiscall。也就是说StartThread()函数的第二个参数要求函数是__thiscall调用方式,而在代码中将StartThread()函数的第二个参数指定为_cdecl方式,因此调试时报错。
3 问题解决
将调用StartThread()函数的代码修改为
StartThread<CMyDlg, DWORD>(this, &CMyDlg::ThreadAccept);
将StartThread()函数的第二个参数设置类成员函数,即将调用方式改为__thiscall。
4 问题扩展
4.1 函数指针
函数指针是指向函数而非指向对象的指针。像其它指针一样,函数指针也指向某个特定的类型。函数类型由其返回类型以及形参表确定,而与函数名无关。例如:
bool (*pf)(const int&, const int&);
以上语句将pf声明为指向函数的指针,它所指向的函数带有两个const int&类型的形参和bool类型的返回值。
类成员函数指针的定义与上述代码类似
bool (CMyClass::* pf)(const int&, const int&)
以上代码定义了CMyClass类的成员函数的指针。
4.2 函数调用方式
函数常见的调用方式有_cdecl、_stdcall和__thiscall等。
_stdcall调用方式一般用于Win32 API函数中。函数采用从右向左的压栈方式,由函数本身在退出时清空堆栈;_cdecl调用方法是C和C++函数的默认调用方式。函数采用从右向左的压栈方式,由该函数的调用者来清空堆栈;__thiscall调用方式用在类的成员函数中,函数采用从右向左的压栈方式,在Visual C++2005之前的版本汇总,由于__thiscall不是关键字,程序无法显式指定thiscall调用方式。