静态数据成员和静态数据成员函数

article/2025/5/11 13:22:18

c++中的static静态数据成员和静态成员函数应该是让大家比较头疼的东西,好像也是找工作公司面试中常常问到的东西。我自己也深有体会,在学习c++的过程中,总感觉static很烦人,但是又是一个必须懂的东西,所以今天就对静态数据成员和静态成员函数坐下小结哈!


一、静态数据成员

1.静态数据成员怎么去定义?

在类中声明静态数据成员很简单,是以static关键字表明即可,如下所示

[cpp]  view plain copy
  1. class Test{  
  2. private:  
  3.     //静态数据成员  
  4.     static int a;  
  5. };  

a就是静态数据成员了,在类中只能声明可是不能定义哈!

要对静态数据成员定义和初始化必须在类的外面也就是在全局作用域中定义,如果定义不给出初值,则默认初值为0

[cpp]  view plain copy
  1. class Test{  
  2. public:  
  3.     int GetA() const{return a;}  
  4. private:  
  5.     //静态数据成员  
  6.     static int a;  
  7. };  
  8. //int Test::a;如果这样定义不赋予初值则初值为零  
  9. int Test::a = 1;  
  10. #include <iostream>  
  11. int main()  
  12. {  
  13.     Test T;  
  14.     std::cout << T.GetA() << std::endl;  
  15. }  

定义时一定要在全局作用域中定义,一定不要在类中定义!

静态数据成员甚至在类没有任何对象的时候都可以访问,静态成员可以独立访问,无需依赖任何对象的建立

另外,不要试图在头文件中定义(初始化)静态数据成员。在大多数的情况下,这样做会引起重复定义这样的错误。即使加上#ifndef #define #endif或者#pragma once也不行。


2.静态数据成员被类的所有对象共享,包括该类的派生类对象,基类对象和派生类对象共享基类的静态数据成员

答:静态数据成员不属于任何对象,类的静态数据成员的存在不依赖于任何类对象的存在,静态数据成员是由类的所有对象共享的。例子如下:

[cpp]  view plain copy
  1. class Base{  
  2. public:  
  3.     //静态数据成员  
  4.     static int a;  
  5. };  
  6. class Derived : public Base{  
  7.   
  8. };  
  9. //int Test::a;如果这样定义不赋予初值则初值为零  
  10. int Base::a;  
  11. #include <iostream>  
  12. int main()  
  13. {  
  14.     Base B;  
  15.     Derived D;  
  16.     B.a++;  
  17.     std::cout << B.a << std::endl;  
  18.     D.a++;  
  19.     std::cout << D.a << std::endl;  
  20.       
  21. }  

打印结果如下:


由打印结果看出来,派生类对象和基类对象都是共享基类的静态数据成员,而基类的所有对象也是共享该静态数据成员,且该静态数据成员应该在全局作用域中定义,可以赋予初值也可以不赋予初值,如果不赋予初值,静态数据成员有其默认值。


3.静态数据成员可以作为成员函数的默认形参,而普通数据成员则不可以

答:不多说,直接看例子马上就明白了哈!

[cpp]  view plain copy
  1. class Test{  
  2. public:  
  3.     //静态数据成员  
  4.     static int a;  
  5.     int b;  
  6.     void fun_1(int i = a);//正确  
  7.     void fun_2(int i = b);//报错  
  8. };  


4.静态数据成员的类型可以是所属类的类型,而普通数据成员则不可以。普通数据成员的只能声明为 所属类类型的 指针或引用

答:这个也不多说,直接看例子就可以懂什么意思哈!

[cpp]  view plain copy
  1. class Test{  
  2. public:  
  3.     //静态数据成员  
  4.     static Test a;//正确  
  5.     Test b;//报错  
  6.     Test *pTest;//正确  
  7.     Test &m_Test;//正确  
  8.     static Test *pStaticObject;//正确  
  9. };  


5.静态数据成员在const函数中可以修改,而普通的数据成员是万万不能修改的哈!

答:看个例子

[cpp]  view plain copy
  1. class Test{  
  2. public:  
  3.     Test():b(0){}  
  4.     //静态数据成员  
  5.     static int a;//正确  
  6.     int b;  
  7.     void test() const  
  8.     {  
  9.         a++;  
  10.         b++;//const指的不能修改当前调用该函数对象的数据成员  
  11.     }  
  12. };  
  13. int Test::a;  

const修饰的时当前this指针所指向的对象是const,但是静态数据成员不属于任何类的对象,它被类的所有对象修改,所以this指针不修饰静态的数据成员,所以可以更改。

二、静态成员函数

静态成员函数的声明也很简单,就是在类的成员函数前加上static关键字即可,和静态成员一样,静态成员函数也是属于类的,它并不属于任何对象,当调用静态成员函数时应该使用类名和域运算符“∷”,当然也可以使用对象调用操作,但是这样的操作并不意味着静态成员函数属于这个对象,它只是被这个对象共享而已,这样也就决定了静态成员函数中是不能访问本类中的非静态数据成员的,它是不能访问非静态数据成员的,在c++中静态成员函数主要用来访问静态数据成员而不访问非静态数据成员

1.静态成员函数不能调用非静态成员函数,但是反过来是可以的

2.静态成员函数没有this指针,也就是说静态成员函数不能使用修饰符(也就是函数后面的const关键字)

3.静态成员函数的地址可用普通函数指针储存,而普通成员函数地址需要用 类成员函数指针来储存。


总结:其实声明为静态,不论是静态数据成员还是静态成员函数,它们都是不依赖于对象而存在的,类在定义后并不分配存储空间,而是在定义类的对象的时候才分配存储空间,相反静态的数据成员和静态的成员函数是已经在内存中开辟了内存空间了,所以静态数据成员可以独立的访问在任何类对象没有建立起来都可以访问,并且静态成员函数不可以调用非静态成员函数,因为非静态成员函数只有在类对象建立以后才可以调用,相反则是可以的。我觉得当对某个判断产生怀疑的时候应该去测试,只有验证了才知道是不是对的哈!


为了能更好阐释静态数据成员和静态成员函数,然后在网上搜了博客,感觉有些例子不错(因找不到最初的出处,所以无法注明请原作者谅解),所以就拿来给大家参考一下哈!

关于玩篮球的例子很能明显解释静态数据成员和静态成员函数到底是怎么回事

你们班里面有10个人(10个比如高一一班的对象),体育老师分给你们一个篮球(静态成员函数),你们每个人都带了一个篮球(非静态成员数),你们都很小气,自己的球只能自己拍,要是5对5打比赛,那就只能用那个静态的篮球了(每个人都可以拿来用,但是带来的影响是对全体的)。因此,我可以说那个篮球是高一一班的成员。所以也就是说:静态成员函数是类的成员函数(因为高一二班就不能拿来玩),但是这个篮球最后还是要还给老师的,任何私人不得占有。希望这样你能明白,其实在内存空间里面说白了静态的成员的内存是唯一的一份,就是当你在类外声明他时开辟的,但是非静态函数的空间分配是在你实例化对象时创建的。

为了使大家更好的理解这两个概念,还是老样子用代码来说明上面文字说明的这一切哈!

关于学生类的例子

[cpp]  view plain copy
  1. //定义Student类  
  2. #include <iostream>  
  3. class Student                    
  4. {  
  5. public:  
  6. //定义构造函数  
  7. Student(int n,int a,float s):num(n),age(a),score(s){ }        
  8. void total();  
  9. //声明静态成员函数  
  10. static float average();        
  11. private:  
  12.     int num;  
  13.     int age;  
  14.     float score;  
  15.     //静态数据成员,累计学生的总分  
  16.     static float sum;   
  17.     //静态数据成员,累计学生的人数  
  18.     static int count;             
  19. };  
  20. //在全局作用域对静态数据成员初始化,如果不赋予初值,则使用其默认值零  
  21. float Student::sum;                       
  22. int Student::count;  
  23. //定义非静态成员函数  
  24. void Student::total()                      
  25. {  
  26.     //累加总分  
  27.     sum+=score;  
  28.     //累计已统计的人数  
  29.     count++;                                 
  30. }  
  31. //定义静态成员函数  
  32. float  Student::average()                    
  33. {  
  34.     return(sum/count);  
  35. }  
  36. int main()  
  37. {  
  38.     Student stud[3]={      
  39.     //定义对象数组并初始化  
  40.     Student(1001,18,70),  
  41.     Student(1002,19,78),  
  42.     Student(1005,20,98)  
  43. };  
  44. int n;  
  45. std::cout<<"please input the number of students: ";  
  46.  //输入需要求前面多少名学生的平均成绩  
  47. std::cin>>n;                                
  48. //调用3次total函数  
  49. for(int i=0;i<n;i++)  
  50. {  
  51.     stud[i].total();  
  52. }  
  53. //调用静态成员函数  
  54. std::cout<<"the average score of "<<n<<" students is "<<Student::average( )<<std::endl;  
  55. return 0;  
  56. }  

打印输出如下:


对上面的代码做以下说明:

首先,在主函数中定义了对象数组,存放每个学生的编号、年龄和成绩,其中sum和count是要累计所有学生的总成绩和总的学生人数,我们定义成了静态数据成员,在学生类的成员函数中,我们定义了普通的total成员函数,用来计算所有学生的总成绩和总的学生人数,另外,定义了静态成员函数average,学生类的设计大概如此

在全局作用域对类中静态数据成员进行了定义,但未赋予初值,这意味着我们采用其默认值。

在类的普通成员函数toal中可以引用静态数据成员sum和count,可见类的所有成员函数都可以引用类的静态数据成员。

在类的静态成员函数average中,只能引用类的静态数据成员,不能引用非静态数据成员。

在主函数中我们调用类的非静态成员函数时只能通过类对象来调用,如stu[i].total,但是对于静态成员函数可以直接通过类名+作用域符号来调用,如

Student::average。

原文:http://blog.csdn.net/computer_liuyun/article/details/29235111


http://chatgpt.dhexx.cn/article/GXDQVnqD.shtml

相关文章

静态数据成员(C++)

目录 一、静态数据成员 1.1、定义 1.2、声明 1.3、初始化 1.4、普通访问 1.5、对象访问 二、静态成员函数 一、静态数据成员 1.1、定义 我们都知道&#xff0c;类是对具有相同属性和相同行为的一组对象的描述。 有时侯&#xff0c;我们希望每定义一个对象&#xff0c…

C语言文件 open函数和fopen函数

open 头文件&#xff1a; #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>定义函数&#xff1a; int open(const char * pathname, int flags); int open(const char * pathname, int flags, mode_t mode);函数说明&#xff1a; 参数1…

VS中fopen_s函数的用法(fopen函数的扩展)

使用方法&#xff1a; 首先看fopen的代码&#xff1a; FILE* fp null; fp fopen(filename,"w") if(fp!null) { // 打开文件成功 }再来看fopen_s的用法&#xff1a; FILE* fp null; errno_t err 0; err fopen_s(&fp,filename,"w") if(err0) { /…

Vxworks或Workbench编译环境下fopen函数的用法

Vmware虚拟机下建立了Vxwork操作系统&#xff0c;Workbench连接对应的Vxworks操作系统进行编程&#xff0c;在此环境下进行编译c或者c语言过程中&#xff0c;用fopen或fprintf将变量输出至文件&#xff0c;过程中要注意的是&#xff0c;此时的Vxworks操作系统没有与Windows的c、…

fopen()函数的使用方法

语法&#xff1a; FILE *fopen(const char *filename, const char *mode); 返回值&#xff1a; fopen函数返回新打开文件的文件指针&#xff1b; 如果此文件不能打开&#xff0c;则返回NULL指针。 表格清晰可见&#xff1a; 模式描述文件可否存在"r"打开文件仅供…

c语言中fopen的作用,c语言fopen函数的用法

在c语言中可以使用“fopen()”函数打开一个文件&#xff0c;该函数用于打开一个文件&#xff0c;其语法是“open("file a","r");”&#xff0c;其参数r表示只读属性。 fopen函数是打开一个文件&#xff0c;其调用的一般形式为&#xff1a; 文件指针名fopen…

fopen函数的用法示例_在C和C ++中使用fopen()函数的用法以及示例

fopen函数的用法示例 In C and C++ programming languages fopen() function is used to open files and make operations like add, update, create for data. In this tutorial we will learn the syntax, usage and errors about the fopen() function. 在C和C ++编程语言中…

php fopen函数php,fopen函数介绍与使用方法详解

在我们的PHP开发中会经常遇到fopen()和file_get_contents(),相信很多同学都发现这两个函数基本上都差不多,那么我们今天就来讲讲php fopen()和file_get_contents()的区别到底再哪,废话少说了,一起来看看吧!php中读取文件可以使用fopen和file_get_contents这两个函数,二者之…

php fopen函数php,php fopen函数用法(打开创建文件)_PHP教程 - fopen

php教程 fopen函数用法(打开创建文件) 在很多时间我们都需要创建文件特别是生成静态页面的时间,我们在php中就常常会用到fopen这个函数来新建文件,它的原是是如何文件存在就追加,不存在可以创建,下面来了很多参数... php教程 fopen函数用法(打开创建文件) 在很多时间我们都…

C语言fopen函数的用法

在C语言中&#xff0c;操作文件之前必须先打开文件&#xff1b;所谓“打开文件”&#xff0c;就是让程序和文件建立连接的过程。 打开文件之后&#xff0c;程序可以得到文件的相关信息&#xff0c;例如大小、类型、权限、创建者、更新时间等。在后续读写文件的过程中&#xff0…

《java核心技术卷I》

《java核心技术卷I》java老师讲课的内容PPT代码基本是来自于这里&#xff0c;感觉还不错&#xff0c;里面的代码也是循序渐进的。 这本书本身也是老师开始讲课时推荐的或者说参考的书的第一本。

java核心技术卷1学习思维导图

java核心技术卷1学习思维导图 java核心技术卷&#xff11;学习java基础 java对象与类基础知识 面向对象java 继承 面向对象java 接口和内部类 异常、日志、断言和调试 泛型程序设计 集合

《Java 核心技术 卷1》 笔记 第六章 接口和内部类(6) 静态代理

6.5 代理 啥是代理&#xff1f;代理人就是替你办事的那个人。比如点了外卖&#xff0c;外卖小哥就是你取餐的代理人。代理除了能完成既定任务&#xff0c;还可以完成额外任务。比如&#xff0c;你留言让他给你带瓶可乐。代理类就是替一个类完成委托地另一个类。 6.5.1 静态代理…

新书推荐 | Java核心技术卷Ⅰ:基础知识(原书第11版)

新书推荐 《Java核心技术卷Ⅰ&#xff1a;基础知识&#xff08;原书第11版&#xff09;》 长按二维码了解及购买 全新第11版&#xff01;针对Java SE9、10、11全面更新&#xff01;Java领域极具影响力和价值的著作之一&#xff0c;与《Java编程思想》齐名&#xff0c;10余年全球…

【Java核心技术卷】谈谈对Java平台的理解

专题 | 谈谈对Java平台的理解 2019年4月24日下午 沉晓 学Java已经快两个月了,结果被问到 "你能给我解释一下什么是Java平台吗?" 结果支支吾吾地说了一大堆,却毫无逻辑可言,感觉超级失败 我觉得很有必要重新谈谈我对Java平台的认识,帮我理清逻辑的同时,希望能够…

对《Java核心技术卷一》读者的一些建议

思想不会变&#xff0c;所以《Java编程思想》还停留在第 4 版&#xff08;2007 年&#xff09;&#xff1b;而技术是要更新迭代的&#xff0c;所以《Java核心技术卷一》来到了第十版&#xff08;2016 年&#xff09;。 我们来看一下《Java核心技术卷一》第十版的大纲。 前九章…

Java核心技术卷1基础知识课程-专题视频课程

Java核心技术卷1基础知识课程—2人已学习 课程介绍 Java核心技术入门视频培训课程&#xff1a;该教程系统全面讲解Java语言的核心概念&#xff0c;语法&#xff0c;重要特性和开发方法&#xff0c;讲解Java开发工具跟编程思想、用Java开发具体的系统程序&#xff0c;让…

Java核心技术卷II:高级特性

网站 更多书籍点击进入>> CiCi岛 下载 电子版仅供预览及学习交流使用&#xff0c;下载后请24小时内删除&#xff0c;支持正版&#xff0c;喜欢的请购买正版书籍 电子书下载(皮皮云盘-点击“普通下载”)购买正版 封页 内容简介 本书是Java领域有影响力和价值的著作之…

# java 核心技术卷1 (原书第11版)通读 第一章:java的基本程序设计结构

前言&#xff1a; 我是一名前端开发人员&#xff0c;因为想自学java&#xff0c;根据网络上的推荐顺序&#xff0c;决定从呼声最高的 java 核心卷 11版 读起&#xff08;PS:其实12版已经出来了&#xff0c;但是只有实体书&#xff0c;没有电子版呀。实体书太贵了&#xff0c;7…