静态数据成员和静态成员函数

静态类成员包括静态数据成员和静态函数成员两部分。

与全局变量相比,优势:
1. 静态数据成员仍然是在类域名字空间,没用进入程序的全局名字空间,因此不存在与程序中其他全局名字冲突的可能
2. 可以实现信息隐藏,静态数据成员可以是private成员,全局变量不行

静态数据成员: 
    静态数据成员必须在类定义外初始化,但const静态数据成员除外,const静态数据成员可以在类体中初始化

 class c1
 {
 public:
 
 private:
   static int num;
   static const  string name = "chio";
 };

  int c1::num = 20;//类外定义并且初始化
  const string c1::name ; //仍然需要在类体外定义

  静态数据成员被 类 的所有对象所共享,包括该类派生类的对象。即派生类对象与基类对象共享基类的静态数据成员。

静态成员函数:

   类成员函数(无论是static成员函数或非static成员函数)都可以直接访问static数据成员,但是static成员函数只能访问static数据成员。因为静态成员函数不含this指针。

   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都进行存取呢(那不就是侵犯私隐了吗)。


我们会经常以“类名::类成员函数”这种方法来调用一个函数(当然我不是说只有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()由始至终只有一个,无论类级的调用,还是对象级的调用,都是合情合理的。 

类的静态成员是属于类的而不是属于哪一个对象的,所以静态成员的使用应该是类名称加域区分符加成员名称的,在上面的代码中就是Point::Init,虽然我们仍然可以使用对象名加点操作符号加成员名称的方式使用,但是不推荐的,静态态类成员的特性就是属于类而不专属于某一个对象。

静态数据成员可以成为成员函数的可选参数,而普通数据成员则不可以:

class base{
public :
static int _staticVar;
int _var;
void foo1(int i=_staticVar);//正确,_staticVar为静态数据成员
void foo2(int i=_var);//错误,_var为普通数据成员 //_var不能独立于所属对象而使用。
};

static数据成员的类型可以是其所属类,而非static数据成员类型只允许为该类的指针或引用:

1 class Bar
2 {
3 public
4     //
5 private:
6     static Bar mem1;//ok
7     Bar *mem2;//ok
8     Bar mem3; //error
9 };


静态成员函数不可以同时声明为 virtual、const、volatile函数:

class base{
virtual static void func1();//错误
static void func2() const;//错误
static void func3() volatile;//错误
};
只在类体的函数声明前加static, 类体外函数定义不能指定关键字static

猜你喜欢

转载自1527zhaobin.iteye.com/blog/1607958
今日推荐