C++ Primer 类 12.6 static

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

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

 

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

 

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

[cpp] view plain copy
  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()改为:

[cpp] view plain copy
  1. void main()  
  2. {  
  3.     Point pt;  
  4.     pt.init();  
  5.     pt.output();  
  6. }  

编译通过。

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

 

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

[cpp] view plain copy
  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. }  

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

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

我们知道,当调用一个对象的成员函数(非静态成员函数)时,系统会把当前对象的起始地址赋给 this 指针。而静态成员函数并不属于某一对象,它与任何对象都无关,因此静态成员函数没有 this 指针。既然它没有指向某一对象,就无法对该对象中的非静态成员进行访问。

可以说,静态成员函数与非静态成员函数的根本区别是:非静态成员函数有 this 指针,而静态成员函数没有 this 指针。由此决定了静态成员函数不能访问本类中的非静态成员。

结论3:静态成员函数中不能引用非静态成员。

注意:静态成员函数不能被声明为virtual。


注意: 与数据成员不同,static 与 const 不能同时修饰成员函数

原因:const 修饰符用于表示函数不能修改成员变量的值,该函数必须是含有 this指针 的类成员函数,函数调用方式为 __thiscall ,而 static 函数是不含有this指针 的,调用规约是 __cdecl 或 __stdcall ,两者是冲突的。

 

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

[cpp] view plain copy
  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:类的非静态成员函数可以调用用静态成员函数,但反之不能。

 

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

[cpp] view plain copy
  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. }  

按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时出错。

 

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

[cpp] view plain copy
  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. }  

程序将输出:

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

原文地址:http://blog.csdn.net/morewindows/article/details/6721430

http://blog.csdn.net/woxiaohahaa/article/details/51319997

C/C++中extern关键字详解

在C语言中,修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。extern声明不是定义,即不分配存储空间。 先来看一段代码 /* basic_stdy...
  • big_bit
  • big_bit
  • 2016年06月06日 15:54
  • 379

QTime类

QTime类参考 QTime类提供了时钟时间功能。详情请见…… #include qdatetime.h> 所有成员函数的列表。 公有成员 QTime() QTime( int...

C++primer plus第六版课后编程题答案12.6

myQueue,cpp不变 main126.cpp #include #include "myQueue.cpp" #include #include using namespace std...

C++ Primer Plus第六版编程练习12.6解答

queue.h // queue.h -- interface for a queue #ifndef QUEUE_H_ #define QUEUE_H_ // This queue will co...

C++primer plus第六版课后编程练习答案12.5与12.6

bank是第五题的实现,bank1是第六题的实现#ifndef QUEUE_H_ #define QUEUE_H_ class Customer { private: int arrive; i...

C++12.6 static 数据成员、static成员函数

简介==================================================================================== 对于特定类类型的全体对象而...

c++ primer 学习笔记23 友元 static类成员

友元机制允许一个类将对其非公有成员的访问权授予指定的函数或类。友元的声明以关键字 friend 开始。它只能出现在类定义的内部。友元声明可以出现在类中的任何地方:友元不是授予友元关系的那个类的成员,所...

c++ primer 学习笔记:类之static 类成员

对于特定类类型的全体对象而言,访问一个全局对象有时是必要的。也许,在程序的任意点需要统计已创建的特定类类型对象的数量;或者,全局对象可能是指向类的错误处理 例程的一个指针;或者,它是指向类类型对象的...

类中的static 数据成员和c++ primer中提到的static的深入思考

类的静态数据成员可以在class的定义中直接初始化,但要清楚:这只是声明并给它提供了一个初值而已,还必须在某一个编译单元中把它定义一次(即分配内存)。如在   C++ primer中出现的...
  • lifu119
  • lifu119
  • 2012年03月07日 19:34
  • 1266

c++primer 3/6---static

static 数据成员的类型可以是该成员所属的类类型。非 static 成员被限定声明为其自身类对象的指针或引用: class Bar { public: // ...
  • G_rrrr
  • G_rrrr
  • 2012年03月06日 15:16
  • 448
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++ Primer 类 12.6 static
举报原因:
原因补充:

(最多只允许输入30个字)