原文地址http://blog.csdn.net/danky/article/details/1429249
自定义的术语:类级成员(class level member)和对象级成员(object level member)。我不知道在C++领域里是否已经有这样的术语,只是我觉得这两个术语可以很好地帮助我们理解static member function。在这里可以就有人想指正我了:本来成员(member)就是类独有的一部分,还分什么类级和对象级的。但我相信如果你看完本文后,你原来对static member function的那种一知半解,会演变成现在的“原来是这么一回事”的话,你会觉得这是非常棒的两个东西。所谓的类级成员就是指该成员是属于类拥有的,一个类只有一个的;而所谓的对象级成员就是指该成员是属于对象自己的,只要产生多少个该类的对象就会产生出多少个这样的成员。如果你还是没有理解其中的意思的话,不要紧,往下看吧,慢慢你就会明白了(其实也没什么,也只是static member与non static member的区别而已,只是我觉得这样更利于理解而已)。
non static member是属于对象级成员函数,也就是说,每个属于该类的对象都会产生一份属于自己的成员。而static member是属于类级成员,也就是说,无论该类产生多少个对象,而这种成员只会产生一个。为什么static member function只能访问static member data呢?就是因为static member data是属于类级成员数据,non static member data是属于对象级成员数据,而static member function是属于类级成员函数,non static member function是属于对象级成员函数。对于一个类级成员函数只能访问到类级成员数据。因为类级成员是共享的,而对象级成员是私有的,私有的数据只能是由私有函数来读取(可不要把这里的共享与私有的关系和灰的声明中的public与private的关系混淆了啊,这里的私有是指对象私有,而后者是指类私有)。
如果对于上面的解释还是不太好理解为什么类级成员只能访问类级成员数据的话,那我就用实际来告诉你为什么私有的对象数据不能由共享的函数来存取了。如有以下类的声明:
class Point
{
public :
void OutPut ();
static void Init ( int, int );
private :
int m_x;
static int m_y;
};
int Point::m_y = 10; //初始化static member data
Point ptA, ptB;
如果有以下函数的定义:
void
Point::OutPut () //正确
{
cout <<"x=" <<x <<endl
<<"y=" <<y <<endl;
}
void
Point::Init ( int x, int y )
{
m_x = x; //错误,m_x是对象级成员数据,Init()是类级成员函数
m_y = y; //正确,m_y和Init()都是类级成员
}
因为ptA和ptB都会产生属于对象自己的m_x(如果定义更多Point的对象,将会产生更多)。对于OutPut()是毫无疑问没问题的,因为ptA和ptB也会产生属于自己OutPut(),对象自己的函数访问属于对象自己数据,这是理所当然的。但Init()只会产生一个,而ptA和ptB都有属于自己m_x(各自互不侵犯),Init()怎么知道应该访问那个m_x呢(准确点应该说编译器怎么知道应该访问那个的m_x),还是对于所有Point的对象的m_x都进行存取呢(那不就是侵犯私隐了吗)。
static member function还有另外一个在一般的语言教材上很少会提到的特点,我们在用MFC的时候会经常以“类名::类成员函数”这种方法来调用一个函数(当然我不是说只有MFC都有这样的调用)。要使用这样的调用方法是需要有一个条件的,就是这个类成员函数一定要是一个static member function。如果你不明白前面的解释的话,你是不会想到这点的。那为什么一定要是static member function才能这样被调用呢,其实原理跟前面是一样的,就是因为static member function只会产生一个。如果你还是想不到为什么的话,那我就用实际来说明一切吧!沿用前面类的声明,如果有以下的用法:
Point::Init ( 5, 5 ); //正确(这里只讨论它的调用方法,不讨论它的定义是否正确),因为Init()是类级成员函数
ptA.Init ( 3, 3 ); //正确,既然Init()是共享的,ptA自然也可以用
Point::OutPut (); //错误,OutPut()是对象级成员函数
ptA.OutPut (); //正确,对象级的函数调用
正如前面所述的,ptA和ptB都会产生属于自己OutPut(),编译器怎么知道应该调用那个对象的OutPut()呢,对象级的函数自然只能使用对象级的调用方法了。对于Init()却是很好理解的,因为Init()由始至终只有一个,无论类级的调用,还是对象级的调用,都是合情合理的