类的静态成员

以下转自http://blog.csdn.net/morewindows/article/details/6721430

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

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

 

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

 

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

  1. class Point  
  2. {  
  3. public:   
  4.     void init()  
  5.     {    
  6.     }  
  7.     static void output()  
  8.     {  
  9.     }  
  10. };  
  11. void main()  
  12. {  
  13.     Point::init();  
  14.     Point::output();  
  15. }  
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:不能通过类名来调用类的非静态成员函数。

 

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

将上例的main()改为:

  1. void main()  
  2. {  
  3.     Point pt;  
  4.     pt.init();  
  5.     pt.output();  
  6. }  
void main()
{
	Point pt;
	pt.init();
	pt.output();
}

编译通过。

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

 

第三个例子,在类的静态成员函数中使用类的非静态成员

  1. #include <stdio.h>   
  2. class Point  
  3. {  
  4. public:   
  5.     void init()  
  6.     {    
  7.     }  
  8.     static void output()  
  9.     {  
  10.         printf("%d\n", m_x);  
  11.     }  
  12. private:  
  13.     int m_x;  
  14. };  
  15. void main()  
  16. {  
  17.     Point pt;  
  18.     pt.output();  
  19. }  
#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:静态成员函数中不能引用非静态成员。

 

第四个例子,在类的非静态成员函数中使用类的静态成员

  1. class Point  
  2. {  
  3. public:   
  4.     void init()  
  5.     {    
  6.         output();  
  7.     }  
  8.     static void output()  
  9.     {  
  10.     }  
  11. };  
  12. void main()  
  13. {  
  14.     Point pt;  
  15.     pt.output();  
  16. }  
class Point
{
public:	
	void init()
	{  
		output();
	}
	static void output()
	{
	}
};
void main()
{
	Point pt;
	pt.output();
}

编译通过。

结论4:类的非静态成员函数可以调用用静态成员函数,但反之不能。

 

第五个例子,使用类的静态成员变量

  1. #include <stdio.h>   
  2. class Point  
  3. {  
  4. public:   
  5.     Point()  
  6.     {    
  7.         m_nPointCount++;  
  8.     }  
  9.     ~Point()  
  10.     {  
  11.         m_nPointCount--;  
  12.     }  
  13.     static void output()  
  14.     {  
  15.         printf("%d\n", m_nPointCount);  
  16.     }  
  17. private:  
  18.     static int m_nPointCount;  
  19. };  
  20. void main()  
  21. {  
  22.     Point pt;  
  23.     pt.output();  
  24. }  
#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();
}

按Ctrl+F7编译无错误,按F7生成EXE程序时报链接错误

error LNK2001: unresolved external symbol "private: static int Point::m_nPointCount" (?m_nPointCount@Point@@0HA)

这是因为类的静态成员变量在使用前必须先初始化。

在main()函数前加上int Point::m_nPointCount = 0;

再编译链接无错误,运行程序将输出1。

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

 

结合上面的五个例子,对类的静态成员变量和成员函数作个总结

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

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

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

 

再给一个利用类的静态成员变量和函数的例子以加深理解,这个例子建立一个学生类,每个学生类的对象将组成一个双向链表,用一个静态成员变量记录这个双向链表的表头,一个静态成员函数输出这个双向链表。

  1. #include <stdio.h>   
  2. #include <string.h>   
  3. const int MAX_NAME_SIZE = 30;    
  4.   
  5. class Student    
  6. {    
  7. public:    
  8.     Student(char *pszName);  
  9.     ~Student();  
  10. public:  
  11.     static void PrintfAllStudents();  
  12. private:    
  13.     char    m_name[MAX_NAME_SIZE];    
  14.     Student *next;  
  15.     Student *prev;  
  16.     static Student *m_head;  
  17. };    
  18.   
  19. Student::Student(char *pszName)  
  20. {    
  21.     strcpy(this->m_name, pszName);  
  22.   
  23.     //建立双向链表,新数据从链表头部插入。   
  24.     this->next = m_head;  
  25.     this->prev = NULL;  
  26.     if (m_head != NULL)  
  27.         m_head->prev = this;  
  28.     m_head = this;    
  29. }    
  30.   
  31. Student::~Student ()//析构过程就是节点的脱离过程     
  32. {    
  33.     if (this == m_head) //该节点就是头节点。   
  34.     {  
  35.         m_head = this->next;  
  36.     }  
  37.     else  
  38.     {  
  39.         this->prev->next = this->next;  
  40.         this->next->prev = this->prev;  
  41.     }  
  42. }    
  43.   
  44. void Student::PrintfAllStudents()  
  45. {  
  46.     for (Student *p = m_head; p != NULL; p = p->next)  
  47.         printf("%s\n", p->m_name);  
  48. }  
  49.   
  50. Student* Student::m_head = NULL;    
  51.   
  52. void main()    
  53. {     
  54.     Student studentA("AAA");  
  55.     Student studentB("BBB");  
  56.     Student studentC("CCC");  
  57.     Student studentD("DDD");  
  58.     Student student("MoreWindows");  
  59.     Student::PrintfAllStudents();  
  60. }  
#include <stdio.h>
#include <string.h>
const int MAX_NAME_SIZE = 30;  

class Student  
{  
public:  
    Student(char *pszName);
    ~Student();
public:
	static void PrintfAllStudents();
private:  
    char    m_name[MAX_NAME_SIZE];  
    Student *next;
	Student *prev;
    static Student *m_head;
};  

Student::Student(char *pszName)
{  
    strcpy(this->m_name, pszName);

	//建立双向链表,新数据从链表头部插入。
    this->next = m_head;
	this->prev = NULL;
	if (m_head != NULL)
		m_head->prev = this;
    m_head = this;  
}  

Student::~Student ()//析构过程就是节点的脱离过程  
{  
	if (this == m_head) //该节点就是头节点。
	{
		m_head = this->next;
	}
	else
	{
		this->prev->next = this->next;
		this->next->prev = this->prev;
	}
}  

void Student::PrintfAllStudents()
{
	for (Student *p = m_head; p != NULL; p = p->next)
		printf("%s\n", p->m_name);
}

Student* Student::m_head = NULL;  

void main()  
{   
	Student studentA("AAA");
	Student studentB("BBB");
	Student studentC("CCC");
	Student studentD("DDD");
	Student student("MoreWindows");
	Student::PrintfAllStudents();
}

程序将输出:

当然在本例还可以增加个静态成员变量来表示链表中学生个数,如果读者有兴趣,就将这个作为小练习吧。

 

--------------------------------------------------------------------------------------------------------------------------------------------

以下转自http://blog.csdn.net/candyliuxj/article/details/4520971

静态成员的特性:

       不管这个类创建了多少个对象,而其静态成员只有一个拷贝(副本),这个拷贝被所有属于这个类的对象共享。

 

一、静态数据成员

 

      定义格式:

            static 数据类型 静态数据成员名;

      初始化格式:

            数据类型 类名::静态数据成员名 =  初始化值;

      公有静态数据成员的访问格式:

            1.  类名::静态数据成员名

            2. 对象.静态数据成员名

            3. 对象指针->静态数据成员名

       说明:

             1. 静态数据成员属于类,普通数据成员属于某一对象;

             2. 在类中不给静态数据成员分配内存空间;

             3. 静态数据成员与静态变量一样,是在编译时创建并初始化,它在该类的任何对象被建立之前就存在;

             4. 静态数据成员不能在类中进行初始化,必须在类外的其他地方为它提供定义;一般在main()开始之前、类的声明之后的特殊地

                 带为它提供定义和初始化;

             5. 私有静态数据成员不能被类外部函数访问,也不能用对象进行访问。

       例子:

               

  1. #include <iostream>   
  2. using namespace std;  
  3.   
  4.   
  5. class KMyClass  
  6. {  
  7. private:  
  8.     static int i;                       //声明i为私有静态数据成员   
  9. public:  
  10.     static int j;                       //声明j为公有静态数据成员   
  11.     int Geti()  
  12.     {  
  13.         return i;  
  14.     }  
  15.     int Getj()  
  16.     {  
  17.         return j;  
  18.     }  
  19. };  
  20.   
  21. int KMyClass::i = 0;                         //静态数据成员初始化   
  22. int KMyClass::j = 0;  
  23.   
  24. int main()  
  25. {  
  26.     KMyClass::j = 200;                   //公有静态数据成员可以在对象定义之前被访问   
  27.     cout<<"KMyClass::j = "<<KMyClass::j<<endl;  
  28.     KMyClass ob1, ob2;  
  29.     cout<<"ob1.i = "<<ob1.Geti()<<endl;  
  30.     cout<<"ob1.j = "<<ob1.Getj()<<endl;  
  31.     cout<<"ob2.i = "<<ob2.Geti()<<endl;  
  32.     cout<<"ob2.j = "<<ob2.Getj()<<endl;  
  33.     ob1.j = 300;                          //公有静态数据成员也可通过对象进行访问   
  34.     cout<<"ob1.j = "<<ob1.Getj()<<endl;   //静态数据成员是对象的共享数据项   
  35.     cout<<"ob2.j = "<<ob2.Getj()<<endl;  
  36.     return 0;  
  37. }  

             程序结果:

                    MyClass::j = 200;

                    ob1.i = 0;

                    ob1.j = 200;

                    ob2.i = 0;

                    ob2.j = 200;

                    ob1.j = 300;

                    ob2.j = 300;

 

二、静态成员函数

     

      定义格式:

            static 返回类型 静态成员函数名(实参表);

      公有静态数据成员的访问格式:

            1.  类名::静态成员函数名(实参表)

            2. 对象.静态成员函数名(实参表)

            3. 对象指针->静态成员函数名(实参表)

       说明:

             1. 静态成员函数可以定义成内嵌的,也可以在类外定义(在类外定义时,不要用static前缀);

             2. 一般情况下,静态成员函数主要用来返回全局变量或同一个类中的静态数据成员(当它与静态数据成员一起使用时,达到了对同

                 一个类中对象之间共享数据进行维护的目的);

             3. 编译系统将静态成员函数限定为内部连接,即,与现行文件相连接的其他文件中的同名函数不会与该函数发生冲突,维护了该函

                 数使用的安全性,这是使用静态成员函数的另一个原因;

             4. 在一般的成员函数中,都隐含有一个this指针,用来指向对象自身,而在静态成员函数中是没有this指针的,因为它不与特定的

                 对象想联系,调用时使用如下格式较好:     类名::静态成员函数名(); 

             5. 私有静态成员函数不能被类外部函数和对象访问。

        例子:

              

  1. #include <iostream>    
  2. using namespace std;  
  3.   
  4. class Small_Cat  
  5. {  
  6. private:  
  7.     double weight;  
  8.     static double total_weight;  
  9.     static double total_number;  
  10. public:  
  11.     Small_Cat(double w)  
  12.     {  
  13.         weight = w;  
  14.         total_weight += w;  
  15.         total_number++;  
  16.     }  
  17.   
  18.     void Display()  
  19.     {  
  20.         cout<<"The small_cat weights "<<weight<<" pounds/n";  
  21.     }  
  22.   
  23.     static void Total_Disp()               //静态成员函数,显示小猫的只数和总重量   
  24.     {  
  25.         cout<<total_number<<" small_cat total weight "<<total_weight<<" pounds"<<endl;  
  26.     }  
  27. };  
  28.   
  29. double Small_Cat::total_weight = 0;  
  30. double Small_Cat::total_number = 0;  
  31.   
  32. int main()  
  33. {  
  34.     Small_Cat w1(1.8), w2(1.6), w3(1.5);  
  35.     w1.Display();  
  36.     w1.Total_Disp();  
  37.     w2.Display();  
  38.     w2.Total_Disp();  
  39.     w3.Display();  
  40.     w3.Total_Disp();  
  41.     Small_Cat::Total_Disp();  
  42.     return 0;  
  43. }  

            程序结果:

                 The small_cat weights 1.8 pounds

                 3 small_cat total weight 4.9 pounds 

                 The small_cat weights 1.6 pounds

                 3 small_cat total weight 4.9 pounds 

                 The small_cat weights 1.5 pounds

                 3 small_cat total weight 4.9 pounds 

                 3 small_cat total weight 4.9 pounds 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值