以上三种情况的代码语法上没有显着的错误,在一些较早的编译环境中,如,VC++ 4.0, 通常可以编译通过,或至多给出问题提醒(Warning)。后来的编译工具,如,VC++6.0和其他一些常用的C++编译软件,不能通过以上代码的编译, 并指出错误如下(以第三种情况用VC++ 6.0编译为例):
error C2664: 'Memberfun1' : cannot convert parameter 1 from 'void (void)' to 'void (__cdecl *)(void)'
None of the functions with this name in scope match the target type
即:Memberfun1参数中所调用的函数类型不对。
按照以上提示,仅通过改变函数的类型无法消除错误,但是,如果单将这几个函数从类的定义中拿出来,不作任何改变就可以消除错误通过编译, 仍以第三种情况为例,以下代码可通过编译:
#include <stdlib.h> void Memberfun1( void (* f2)( ) ) { f2( ) ;} //原成员函数1调用成员函数//2。 void Memberfun2( ) { printf("%s \n","Calling Test3::Memberfun2 OK");} //原成员函数2。 void Memberfun3( ) { Memberfun1( Memberfun2);} int main( ) { Memberfun3 (); return 0; } |
第1、 2种情况和第3种情况完全相同。
由此可以的得出结论,以上三种情况编译不能通过的原因表面上并不在于函数类型调用不对,而是与 “类”有关。没通过编译的情况是用函数指针调用了 “类”的成员函数,通过编译的是用函数指针调用了非成员函数,而函数的类型完全相同。那么, “类”的成员函数指针和非成员函数指针有什么不同吗?
在下面的程序中,用sizeof()函数可以查看各种“类”的成员函数指针和非成员函数指针的长度(size)并输出到屏幕上。
#include "stdafx.h" #include <iostream> #include <typeinfo.h> class Test; //一个未定义的类。 class Test2 //一个空类。 { }; class Test3 //一个有定义的类。 { public: //... void (* memberfun)(); void Memberfun1( void (* f2)( ) ) { f2( ) ;} //成员函数1调用成员函数//2。 void Memberfun2( );//成员函数2。 //… }; class Test4: virtual Test3 ,Test2 //一个有virtual继承的类(derivative class)。 { public: void Memberfun1( void (* f2)( ) ) { f2( ) ;} }; class Test5: Test3,Test2 //一个继承类(derivative class)。 { public: void Memberfun1( void (* f2)( ) ) { f2( ) ;} }; int main() { std::cout <<"一般函数指针长度= "<< sizeof(void(*)()) << '\n'; std::cout <<"-类的成员函数指针长度-"<<'\n'<<'\n'; std::cout <<"Test3类成员函数指针长度="<< sizeof(void(Test3::*)())<<'\n'<<'\n'; std::cout <<"Test5类成员函数指针长度="<<sizeof(void (Test5:: *)())<<'\n'; std::cout <<"Test4类成员函数指针长度="<<sizeof(void (Test4:: *)())<<'\n'; std::cout <<"Test类成员函数指针长度="<<sizeof(void(Test::*)()) <<'\n'; return 0; } |
输出结果为(VC++6.0编译,运行于Win98操作系统,其他操作系统可能有所不同):
一般非成员函数指针长度= 4
-类的成员函数指针长度-
Test3类成员函数指针长度=4
Test5类成员函数指针长度=8
Test4类成员函数指针长度=12
Test类成员函数指针长度=16