类成员函数指针区别于用法

通常的函数指针大家已经非常熟悉了。但我们今天讨论一下类成员函数指针的用法。

今天我们来看一下成员函数指针,加入我们想要声明一个 void CTest::Show()成员函数指针类型,那么我们一般的做法是:

typedef void(CTest::*pShow)();

从上面可以看出一些和一般函数指针类型不同的地方。让我们把他和一般的函数声明比较一下。下面是一般的函数声明:

typedef void(*pShow)();

我们可以看出成员函数指针和一般函数指针的不同,那就是成员函数指针声明时加上类限制。这会起到什么作用呢?和类成员函数一样,那就是编译器会在编译的时候在函数指针对应的函数调用中加上this指针。所以类成员函数不能单独调用,一定要注意。必须与类对象配合调用。

 

下面是一个简单的成员函数指针类型的使用例子:

#include "stdafx.h"
#include <iostream>

using namespace std;
class Test

{

 int sum;

public:

 Test():sum(0){}

 int Add(int a,int b) {return (sum = a + b);}

 void Show() {cout<<"Show()";}

};

 

 

//////////////////////////////////////////////////////////cpp//////////////////////////////////////////////////////////////////////////

 

 

typedef void(Test::*pShow)();
typedef int(Test::*pAdd)(int,int);


int _tmain(int argc, _TCHAR* argv[])

{

 Test t;

 pShow Show=&Test::Show;
 pAdd  Add=&Test::Add;


 (t.*Show)();
 cout<<(t.*Add)(2,5);

}

结果:Show()7

注意其中特别的语法:

1:给指针变量赋值时,要在用来赋值的成员函数名前面加'&'符号。

2:注意(t.*Add)(2,5)可不能能写成t.*Add(2,5);因为括号的优先级比*高。所以要写成(t.*Add)(2,5)或者(t.Add)(2,5)。后者之所以可以,因为函数名本身可以当地址,但C++同时也支持&函数名为取函数地址。这关系到如果看待函数名以处理函数指针的重要问题。

 

既然说到成员函数指针的那么,我们很可能会想到它是否具有向类的函数一样的特殊性质,特别是虚函数?是的,成员函数指针就有虚函数的特性。看下例:

#include "stdafx.h"
#include <iostream>

using namespace std;
class A
{
public:
 virtual void Show() {cout<<"A";}
};

class B:public A
{
public :
 void Show() {cout<<"B";}
};

 

//////////////////////////////////////////////////////////cpp//////////////////////////////////////////////////////////////////////////

 

 

typedef void(A::*pShow)();


int _tmain(int argc, _TCHAR* argv[])

{

 B t;

 pShow Show=(pShow)&A::Show;
 pShow Show=(pShow)&B::Show;

 (t.Show)();
 cin.get();

}

结果:BB

 

通过结果可以看出,虽然声明的基类的虚函数指针,但是函数指针调用时还是根据调用对象来相应的函数,颇像虚函数。所以基类成员函数指针可以根据运行时对象的类型来确定的对应的函数调用。

 

但其中有一个容易忽略的语法:

基类指针=派生类函数地址,这种隐式赋值是不行。也就是说

pShow Show=&B::Show;

编译时不通过的,也就是说C++认为将派生类成员函数名赋给基类成员函数指针是可能存在问题的。可能你会想,我们经常将派生类对象给基类指针啊,

是啊,不过两者不是一回事,考虑的角度不同。

 

前者的解释:基类的函数布局(个数)是派生类的函数布局的子集。所以基类的函数赋给派生类的函数指针时,因为派生类肯定有(public的基类函数)此函数,所以赋值很安全。反过来,你想有可能会出现问题。

后者的解释:基类所做的操作涉及的数据成员不会超出派生类的范围。所以把派生类对象给基类指针,基类来处理没问题。也很安全。反过来呢,你也知道,很危险滴!

 

所以在使用成员函数指针时大家还需多多注意。

上一篇:C++输入输出零散点


下一篇:#define用法总结