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++primer plus第六版课后编程题答案12.6

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

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

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

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

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

c++primer 3/6---static

static 数据成员的类型可以是该成员所属的类类型。非 static 成员被限定声明为其自身类对象的指针或引用: class Bar { public: // ...

C++ primer ----static总结(转载)

地址:http://blog.csdn.net/mishifangxiangdefeng/article/details/7192809一、不在类中的static的使用1.作用1.局部变量被申明为st...

C++ Primer 习题12.38 ~ 12.41 class 中的 static 成员

第12 章主要讲类的一些基本概念. 这几个习题都是跟 class 中的 static 成员相关的. 有如下几点值得注意: 1.static 成员的初始化 (或者说叫 定义 ),紧随 cl...

2017-5-17 C++ primer 笔记 (static和extern的区别和用法)

c++primer笔记 加入光荣的进化吧 第六章! 函数 局部对象 名字有作用域, 对象有生命周期。 名字的作用域是程序文本的一部分,名字在其中可见 对象的生命周期是程序执行过程中...

重温C++ primer 之C++类中的static数据成员,static成员函数

C++类中谈到static,我们可以在类中定义static成员,static成员函数!C++primer里面讲过:static成员它不像普通的数据成员,static数据成员独立于该类的任意对象而存在,...

从头认识java-12.6 接口与类型信息(怎么绕过接口直接调用类的所有方法)

这一章节我们来讨论一下接口与类型信息。在之前的章节里面我们提到接口,父类引用子类对象,然后把方法给缩窄了,但是我们这一章节学习到反射,这个约束就变得没有那么严格。我们来看看下面的例子:package ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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