zoukankan      html  css  js  c++  java
  • c++ 静态成员变量

    在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. }  

    编译出错: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. }  

    编译通过。

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

     

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

    1. #include <stdio.h>  
    2. class Point  
    3. {  
    4. public:   
    5.     void init()  
    6.     {    
    7.     }  
    8.     static void output()  
    9.     {  
    10.         printf("%d ", m_x);  
    11.     }  
    12. private:  
    13.     int m_x;  
    14. };  
    15. void main()  
    16. {  
    17.     Point pt;  
    18.     pt.output();  
    19. }  

    编译出错: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. }  

    编译通过。

    结论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 ", m_nPointCount);  
    16.     }  
    17. private:  
    18.     static int m_nPointCount;  
    19. };  
    20. void main()  
    21. {  
    22.     Point pt;  
    23.     pt.output();  
    24. }  

    按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 ", 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. }  

    程序将输出:

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

    转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/6721430

  • 相关阅读:
    Atitit attilax要工作研究的要素 纪要 方案 趋势 方向 概念 理论
    Atitit 常见每日流程日程日常工作.docx v7 r8f
    Atitit it 互联网 软件牛人的博客列表
    Atitit 信息链(Information Chain)的概念理解 attilax总结
    Atitit 知识点的体系化 框架与方法 如何了解 看待xxx
    Atitit 聚合搜索多个微博 attilax总结
    Atitit 企业知识管理PKM与PIM
    Atitit 项目沟通管理 Atitit 沟通之道 attilax著.docx
    Atitit 项目管理软件 在线服务 attilax总结 1. 项目管理协作的历史 1 1.1. Worktile 406k 1 1.2. Teambition  584k in baidu
    Atitit.每周末总结 于每周一计划日程表 流程表 v8 import 上周遗漏日志补充 检查话费 检查流量情况 Crm问候 Crm表total and 问候
  • 原文地址:https://www.cnblogs.com/dragon2012/p/3146403.html
Copyright © 2011-2022 走看看