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

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

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

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

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()改为:

void main()

{

Point pt;

pt.init();

pt.output();

}

编译通过。

结论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:静态成员函数中不能引用非静态成员。

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

class Point
{
public:   
       void init()
       { 
              output();
       }
       static void output()
       {
       }
};
void main()
{
       Point pt;
       pt.output();
}

编译通过。

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

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

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

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

#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();
}

程序将输出:

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

c++ static静态的更多相关文章

  1. PHP static静态属性和静态方法

    这里分析了php面向对象中static静态属性和静态方法的调用.关于它们的调用(能不能调用,怎么样调用),需要弄明白了他们在内存中存放位置,这样就非常容易理解了.静态属性.方法(包括静态与非静态)在内 ...

  2. android 尽量不要使用static静态变量

    使用静态static静态变量潜在性问题: 1.占用内存,并且内存一般不会释放: 2.在系统不够内存情况下会自动回收静态内存,这样就会引起访问全局静态错误. 3.不能将activity作为static静 ...

  3. PHP之static静态变量详解(一)

    什么是static静态变量?(以下为在C语言中的理解) 静态变量 类型说明符是static. 静态变量属于静态存储方式,其存储空间为内存中的静态数据区(在静态存储区内分配存储单元),该 区域中的数据在 ...

  4. Javase部分回顾(static (静态修饰符),修饰方法,单利的设计模式, 封装)

    static (静态修饰符)        1.修饰成员变量        静态变量的访问方式:            方式一 : 通过对象访问.                对象.变量名      ...

  5. php面向对象中static静态属性和静态方法的调用

    这篇文章主要介绍了php面向对象中static静态属性和静态方法的调用,实例分析了static静态属性和静态方法的原理与调用技巧,需要的朋友可以参考下 本文实例讲述了php中static静态属性和静态 ...

  6. FFmpeg for XP(x86) 2016-03-23 static 静态编译程序

    FFmpeg for XP(x86) 2016-03-23 static 静态编译适用于32位XP系统,能加的扩展都加了,结果文件大小非常大. 最新版加了不少视频和音频滤镜. ffmpeg.20160 ...

  7. Java中static静态关键字的使用

    我们可以基于一个类创建多个对象,每个对象都拥有自己的成员,所有成员变量的值是根据对象而存在的,有些时候我们希望一个类的所有对象共享一个成员,这就用到了static静态关键字 被静态关键字修饰的成员属于 ...

  8. C#中static静态变量的用法

    使用 static 修饰符声明属于类型本身而不是属于特定对象的静态成员static修饰符可用于类.字段.方法.属性.运算符.事件和构造函数,但不能用于索引器.析构函数或类以外的类型 静态全局变量 定义 ...

  9. [转] C# 中的static静态变量

    logitechyan原文关于C#中static静态变量 C#静态变量使用static 修饰符进行声明,在类被实例化时创建,通过类进行访问不带有 static 修饰符声明的变量称做非静态变量,在对象被 ...

  10. 关于C#中static静态变量

    C#静态变量使用static 修饰符进行声明,在类被实例化时创建,通过类进行访问不带有 static 修饰符声明的变量称做非静态变量,在对象被实例化时创建,通过对象进行访问一个类的所有实例的同一C#静 ...

随机推荐

  1. js & 快捷键 & vue bind bug

    js & 快捷键 & vue bind bug how to prevent addEventListener bind many times solution dataset &am ...

  2. sqlserver中where条件加判断

    我想实现如下功能: where case when (@a = null) then 1 = 1 else @a=a and b=@b 但是这样报错,经过翻阅资料找到如下解决方案: where (1 ...

  3. python的N个小功能(图片预处理:打开图片,滤波器,增强,灰度图转换,去噪,二值化,切割,保存)

    ############################################################################################# ###### ...

  4. Java线程Dump分析工具--jstack

    jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使 ...

  5. POJ 2155 Matrix (矩形)

    date:公元2017年7月19日适逢周三: location:清北集训 杭州 point:二维树状数组/二维差分 Matrix Time Limit: 3000MS   Memory Limit:  ...

  6. wazhu之agent manage

      代理生命周期 注册代理 一旦代理程序安装在要监控的计算机上,就必须向Wazuh管理器注册才能建立通信.这可以通过命令行,Authd或RESTful API完成. 注册代理将保留在管理器中,直到用户 ...

  7. 设置nginx日志滚动

    需求:设置nginx每天凌晨12点轮转,系统版本为debian7,nginx版本为tengine2.2.0 1.修改logrotate主配置文件,打开压缩和以时间为后缀命名 # vim /etc/lo ...

  8. python学习(十八)爬虫中加入cookie

    转载自:原文链接 前几篇文章介绍了urllib库基本使用和爬虫的简单应用,本文介绍如何通过post信息给网站,保存登陆后cookie,并用于请求有权限的操作.保存cookie需要用到cookiejar ...

  9. hihocoder #1162 矩阵加速dp

    #1162 : 骨牌覆盖问题·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 前两周里,我们讲解了2xN,3xN骨牌覆盖的问题,并且引入了两种不同的递推方法.这一次我 ...

  10. 总结: 《jQuery基础教程》 5-完结

    第5章:操作DOM HTML属性和DOM属性:attr()和prop() 获取表单控件的值:val() DOM操作方法的归纳: (1) 要在HTML中创建新元素,使用$()函数.(2) 要在每个匹配的 ...