浅谈C++类静态数据成员与类静态函数成员

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

 

一、静态数据成员: 


当将类的某个数据成员声明为static时,该静态数据成员只能被定义一次,而且要被同类的所有对象共享。各个对象都拥有类中每一个普通数据成员的副本,但静态数据成员只有一个实例存在,与定义了多少类对象无关。静态方法就是与该类相关的,是类的一种行为,而不是与该类的实例对象相关。


与全局变量相比,优势:

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


静态数据成员不能在类中初始化,实际上类定义只是在描述对象的蓝图,在其中指定初值是不允许的。也不能在类的构造函数中初始化该成员,因为静态数据成员为类的各个对象共享,否则每次创建一个类的对象则静态数据成员都要被重新初始化。静态成员不可在类体内进行赋值,因为它是被所有该类的对象所共享的。你在一个对象里给它赋值,其他对象里的该成员也会发生变化。为了避免混乱,所以不可在类体内进行赋值。但constt静态数据成员除外,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是属于对象级成员函数。对于一个类级成员函数只能访问到类级成员数据。因为类级成员是共享的,而对象级成员是私有的,私有的数据只能是由私有函数来读取

解释可见以下实例:

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。如果你不明白前面的解释的话,你是不会想到这点的。那为什么一定要是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()由始至终只有一个,无论类级的调用,还是对象级的调用,都是合情合理的。

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

class base{ 
virtual static void func1();//错误 
static void func2() const;//错误 
static void func3() volatile;//错误 
}; 


关于静态成员函数,可以总结为以下几点:

出现在类体外的函数定义不能指定关键字static;

静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;

非静态成员函数可以任意地访问静态成员函数和静态数据成员;

静态成员函数不能直接访问非静态成员函数和非静态数据成员(静态成员函数访问非静态数据成员必须通过参数传递的方式得到一个对象名,然后通过对象名来访问);
















  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值