静态成员

        在C++中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。

静态成员的定义或声明要加个关键static。静态成员可以通过类名加域操作符双冒号来使用即<类名>::<静态成员名>

        C++中类的静态成员变量和静态成员函数是个容易出错的地方,本文先通过几个例子来总结静态成员变量和成员函数使用规则,再给出一个实例来加深印象。希望阅读本文可以使读者对类的静态成员变量和成员函数有更为深刻的认识。


案例1:静态成员函数不能访问非静态数据成员

#include "iostream"
using namespace std;
class test
{
private:
     int x;
     int y;
public:
     static int num;
     static int Getnum()
     {
          x+=5;   // 这行代码是错误的,静态成员函数不能调用非静态数据成员,要通过类的对象来调用。
          num+=15;
          return num;
     }
};
int test::num = 10;
int main(void)
{
     test a;
     cout<<test::num<<endl;        //10
     test::num = 20;
     cout<<test::num<<endl;        //20
     cout<<test::Getnum()<<endl;   //35
     cout<<a.Getnum()<<endl;       //50
     system("pause");
     return 0;
}

解析:

通过上例可知:  x+=5;   // 这行代码是错误的
    静态函数成员必须通过对象名来访问非静态数据成员。
    另外,静态成员函数在类外实现时候无须加static关键字,否则是错误的。
    若在类的体外来实现上述的那个静态成员函数,不能加static关键字,这样写就可以了:
     int test::Getnum()
     {
       .........
     }
1、static成员的所有者是类本身和对象,但是多有对象拥有一样的静态成员。从而在定义对象是不能通过构造函数对其进行初始化。
2、静态成员不能在类定义里边初始化,只能在class body外初始化。
3、静态成员仍然遵循public,private,protected访问准则。
4、静态成员函数没有this指针,它不能返回非静态成员,因为除了对象会调用它外,类本身也可以调用。

案例2:静态成员函数可以直接访问该类的静态数据和函数成员,而访问非静态数据成员必须通过参数传递的方式得到一个对象名,然后通过对象名来访问。

class student{
     static int number;
     string name;
piblic:
     static int printNumber(student& s){
    cout<<s.name<<"\n“;
   cout<<s.number<<" total numbers\n";
<span style="white-space: pre;">	</span>}
}
int student::number=0;


class Myclass
{
private:
        int a,b,c;
        static int Sum;    //声明静态数据成员
public:
        Myclass(int a,int b,int c);
        void GetSum();
};
int Myclass::Sum=0;       //定义并初始化静态数据成员
Myclass::Myclass(int a,int b,int c)
{
        this->a=a;
        this->b=b;
        this->c=c;
        Sum+=a+b+c;
}
void Myclass::GetSum()
{
        cout <<"Sum=" <<Sum <<endl;
}
int main(void)
{
        Myclass me(10,20,30);
        me.GetSum();
        system("pause");
        return 0;
}
解析:非静态成员函数可以任意地访问静态成员函数和静态数据成员。非静态成员函数Myclass(int a,int b,int c)和GetSum()都访问了静态数据成员Sum。静态成员函数不能访问非静态成员函数和非静态数据成员。

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


1.出现在类体外的函数定义不能指定关键字static;
2.静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
3.非静态成员函数可以任意地访问静态成员函数和静态数据成员;
4.静态成员函数不能访问非静态成员函数和非静态数据成员;
5.由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;
6.调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,
7. 静态数据成员的用途之一是统计有多少个对象实际存在。

8.当将类的某个数据成员声明为static时,该静态数据成员只能被定义一次而且要被同类的所有对象共享。各个对象都拥有类中每一个普通数据成员的副本,但静态数据成员只有一个实例存在,与定义了多少类对象无关。静态方法就是与该类相关的,是类的一种行为,而不是与该类的实例对象相关。
9.静态数据成员不能在类中初始化,实际上类定义只是在描述对象的蓝图,在其中指定初值是不允许的。也不能在类的构造函数中初始化该成员,因为静态数据成员为类的各个对象共享,否则每次创建一个类的对象则静态数据成员都要被重新初始化。 静态成员不可在类体内进行赋值,因为它是被所有该类的对象所共享的。你在一个对象里给它赋值,其他对象里的该成员也会发生变化。为了避免混乱,所以不可在类体内进行赋值。 静态成员的值对所有的对象是一样的。静态成员可以被初始化,但只能在类体外进行初始化。
              一般形式:数据类型类名::静态数据成员名=初值
          注意:不能用参数初始化表对静态成员初始化。一般系统缺省初始为0。


进阶:


      1.静态成员函数可以脱离对象,直接用类名调用,脱离对象的牵制

   第一个例子,通过类名调用静态成员函数和非静态成员函数

<pre name="code" class="cpp">class Point
{
public:   
       void init()
       { 
       }
       static void output()
       {
       }
};
void main()
{
       Point::init();
       Point::output();
}


编译出错:error C2352: 'Point::init' : illegal call of non-static member function

结论1:不能通过类名来调用类的非静态成员函数。

   

    第二个例子,通过类的对象调用静态成员函数和非静态成员函数

void main()
{
       Point pt;
       pt.init();
       pt.output();
}

编译通过。

结论2:类的对象可以使用静态成员函数和非静态成员函数。


    2.静态成员函数中不能引用非静态成员

#include <stdio.h>
class Point
{
public:   
       void init()
       { 
       }
       static void output()
       {
              printf("%d\n", m_x);
       }
private:
       int m_x;
};
void main()
{
       Point pt;
       pt.output();
}

编译出错:error C2597: illegal reference to data member 'Point::m_x' in a static member function

因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了,就好比没有声明一个变量却提前使用它一样。

结论3:静态成员函数中不能引用非静态成员。但是,类的非静态成员函数可以调用用静态成员函数。

    

    3.类的静态成员变量在使用前必须先初始化

#include <stdio.h>
class Point
{
public:   
       Point()
       { 
              m_nPointCount++;
       }
       ~Point()
       {
              m_nPointCount--;
       }
       static void output()
       {
              printf("%d\n", m_nPointCount);
       }
private:
       static int m_nPointCount;
};
void main()
{
       Point pt;
       pt.output();
}

链接失败,这是因为类的静态成员变量在使用前必须先初始化。main()函数前加上int Point::m_nPointCount = 0;再编译链接无错误,运行程序将输出1

结论:类的静态成员变量必须先初始化再使用。


总结

1.静态成员函数中不能调用非静态成员。

2.非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。

3.静态成员变量使用前必须先初始化(int MyClass::m_nNumber = 0;),否则会在linker时出错。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值