1指向函数的指针的类型
指向函数的指针应该怎样声明?拿两个字符串的比较函数来说:
int strCompare(const string & s1, const string & s2) ;
如果两个字符串相等就返回0,否则,s1< s2返回负数,s1 > s2返回正数其实函数名不是其类型的一部分,函数类型是只由它的返回类型和参数来决定。函数名称只不过是指向函数代码的地址。所以指向函数的指针的类型应该用下面的形式声名:
int (pf)( const string &, const string & );
2初始化和赋值
指向函数的指针可如下被初始化只有当赋值 *** 作符左边指针的参数表和返回类型与右边函数或指针的参数表和返回类型
完全匹配时初始化和赋值才是正确的如果不匹配则将产生编译错误消息在指向函数
类型的指针之间不存在隐式类型转换。
int (pfi)( const string &, const string & ) = strCompare;
int (pfi2)( const string &, const string & ) = &strCompare;
指向函数的指针可以如下被赋值
pfi = strCompare;
pfi2 = pfi;
3调用
如下代码:
#include <iostream>
using namespace std;
int min( int, int );
int (pf)( int, int ) = min;
const int iaSize = 5;
int ia[ iaSize ] = { 7, 4, 9, 2, 5 };
int main()
{
cout << "Direct call: min: "
<< min( ia, iaSize ) << endl;
cout << "Indirect call: min: "
<< pf( ia, iaSize ) << endl;
return 0;
}
int min( int ia, int sz )
{
int minVal = ia[ 0 ];
for ( int ix = 1; ix < sz; ++ix )
if ( minVal > ia[ ix ] )
minVal = ia[ ix ];
return minVal;
}
4函数指针的数组
我们可以声明一个函数指针的数组例如
int (testCases[10])();
将testCases 声明为一个拥有10 个元素的数组每个元素都是一个指向函数的函数指针,该函数没有参数返回类型为int。
上面的声明等价于下面声明:
typedef int (PFV)(); // 定义函数类型指针的typedef
PFV testCases[10];
函数指针的数组可以用一个初始化列表来初始化该表中每个初始值都代表了一个与数
组元素类型相同的函数例如
int lexicoCompare( const string &, const string & );
int sizeCompare( const string &, const string & );
typedef int ( PFI2S )( const string &, const string & );
PFI2S compareFuncs[2] =
{
lexicoCompare,
sizeCompare
};
// 两个等价的调用
pfCompare[ 0 ]( string1, string2 ); // 编写
((pfCompare)[ 0 ])( string1, string2 ); // 显式
5,参数和返回类型
函数参数的类型不能是函数类型函数类型的参数将被自动转换成该函数类型的指针
例如
// typedef 表示一个函数类型
typedef int functype( const string &, const string & );
void sort( string , string , functype );
编译器把sort()当作已经声明为
void sort( string , string ,
int ()( const string &, const string & ) );
上面这两个sort()的声明是等价的
注意除了用作参数类型之外函数指针也可以被用作函数返回值的类型例如
int (ff( int ))( int, int );
该声明将ff()声明为一个函数它有一个int 型的参数返回一个指向函数的指针类型
为
int () ( int, int );
同样使用typedef 名字可以使声明更容易读懂例如下面的typedef PF 使得我们能更
容易地分解出ff()的返回类型是函数指针
typedef int (PF)( int, int );
PF ff( int );
函数不能声明返回一个函数类型如果是则产生编译错误例如函数ff()不能如下
声明
// typedef 表示一个函数类型
typedef int func( int, int );
func ff( int ); // 错误: ff()的返同类型为函数类型
按照fun的声明,它的信息是不会被记录在类型实例里面的,因此派生出来的类实例化后,实体中并没有foo的相关信息,当然被重定义的fun函数也就不会被调用到了。
而f函数中的所用指针的类型型为A,所以就会调用A::fun()。
加上virtual就可以得到你想要的结果了。
class A{
//
virtual void fun(){ cout<<"Member of A:"<<v<<endl;}
//
};
1) 将需要调用的成员函数设为static 类型,如:在前述例子2中,将class Test2 成员函数Compare 定义前加上static 如下(黑体为改变之处):
class Test2{//…int static __cdecl Compare(const void elem1, const void elem2) //成员函数。//其他不变}
改变后的代码编译顺利通过。原因是,static 类型的成员函数与类是分开的,其函数指针也不包含对象信息,与一般函数指针一致。这种方法虽然简便,但有两个缺点:1、被调用的函数成员定义内不能出现任何类的成员(包括变量和函数);2、由于使用了static 成员,类在被继承时受到了限制。
(2) 使用一个函数参数含有对象信息的static 类型的成员函数为中转间接地调用其他成员函数,以例3为例,将类Test3作如下修改(黑体字为修改之处),main()函数不变,则可顺利通过编译:
class Test3{ public: //… void static __cdecl Helper(Test3 test3) { test3->Memberfun2(); } void Memberfun1( void ( f2)(Test3)) { f2(this) ;} //将对象信息传给Helper函数。 void Memberfun2( ) {printf(%s \n,Calling Test3::Memberfun2 OK); } //成员函数2。 void Memberfun3( ) { Memberfun1( Helper);} //…};
这种间接方式对成员函数没有任何限制,克服了第一种方法成员函数不能使用任何类的成员的缺点,但由于有static 成员,类的继承仍受到制约。
(3)使用一个全程函数(global function)为中转间接调用类的成员函数,仍以例3为例,将代码作如下修改(VC++60编译通过):
class Test3;void __cdecl Helper(Test3 test3);class Test3{ public: //… void Memberfun1( void ( f2)(Test3)) { f2(this) ;} //成员函数1调用成员函数//2。 void Memberfun2( ) {printf(%s \n,Calling Test3::Memberfun2 OK); } //成员函数2。 void Memberfun3( ) { Memberfun1( Helper);} //…};void __cdecl Helper(Test3 test3){ test3->Memberfun2();};
这个方法对成员函数没有任何要求,但是需要较多的代码。
可以,通常是这样的
一般遵循面对对象设计原则,其他类希望外部调用的会设计成public,于是你可以很容易地通过指针或者对象名或者引用去调用其它类的public函数
还有其他的情况:
static函数,这个可以全局调用,所以你自然也可以调用。
友元关系,如果你的这个类与需要调用的其他类是友元的关系,那么你可以打破public的限制调用其它类的成员函数
// 函数指针在定义的时候加上号,主要是一个形式
// 表明它可以引用不同的函数
#include <iostream>
using namespace std;
class TA
{
public:
static void fun() { cout << "Hello have fun"; }
void (funp)(); // 一般函数指针这样定义
};
int main()
{
TA ta;
tafunp = TA::fun; // 为函数指针赋值
tafunp(); // 直接用指针变量的名字引用出函数
return 0;
}
因为Klass类内联实现了addCourse函数,这里使用了Course类的方法,因此在编译addCourse函数时,编译器需要知道Course类的完整定义,而不能使用前置声明等方式,也就是说你需要把Course类的定义放到klass前面。或者,你可以把addCourse放到cpp文件里面,不要内联在头文件中实现,然后在cpp文件中引用Course类的定义,这样就可以在这里只用一个前置声明。
你把Set的参数包装下,比如像下面这样:
#include<iostream>
using namespace std;
struct Param{
double x,y;
};
struct CircleParam:public Param{
double z;
};
class Point
{
public:
Point(double p=0,double q=0){X=p;Y=q;cout<<"点构造完成"<<endl;}
Point(Point &p){X=pX;Y=pY;}
virtual void Set(Param p){X=p->x;Y=p->y;}
virtual void Print(){cout<<"( "<<X<<" , "<<Y<<" )";}
virtual double GetArea(){return 0;}
virtual ~Point(){cout<<"点析构函数被调用"<<endl;}
protected:
double X,Y;
};
class Circle:public Point
{
public:
Circle(double p=0,double q=0,double r=0){X=p;Y=q;R=r;cout<<"圆构造完成"<<endl;}
Circle(Circle &p){X=pX;Y=pY;R=pR;}
virtual void Set(Param p){
CircleParam pp=(CircleParam)p;
X=pp->x;Y=pp->y;R=pp->z; cout<<"CircleParam"<<endl;}
void Print(){cout<<"( "<<X<<" , "<<Y<<" ) "<<"半径为:"<<R<<" ";}
double GetArea(){return 3141592653589793238RR;}
~Circle(){cout<<"圆析构函数被调用"<<endl;}
private:
double R;
};
int main(){
Point p=new Circle;
CircleParam pa;
pax=0,pay=0,paz=0;
p->Set(&pa);
system("pause");
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)