由关键字static修饰类体中成员,称为类静态成员(static class member)。类的静态成员为其所有对象共享,不管有多少对象,静态成员只有一份存于公共内存中。静态数据成员被当作该类类型的全局对象。
在类设计中,用关键字static修饰的数据成员为静态数据成员。由该类型实例化的所有对象,共享系统为静态成员分配的一个存储空间,而这个存储空间是程序执行main函数之前分配的,在实例化对象时不再为静态成员分配空间(静态成员数据不在对象空间中)。
示例:
- class Circle
- {
- private:
- double pi; //
- double radius; // 半径
- public:
- Circle(double r = 0.0):pi(3.14),radius(r) {}
- ~Circle() {}
- void area() const
- {
- return pi * radius * radius;
- }
- };
- int main()
- {
- Circle cir(12.23);
- cir.area();
- size_t sz = sizeof(cir);
- return 0;
- }
全局变量:
- double pi = 3.14;
- class Circle
- {
- private:
- double radius; // 半径
- public:
- Circle(double r = 0.0):pi(3.14),radius(r) {}
- ~Circle() {}
- void area() const
- {
- return pi * radius * radius;
- }
- };
类的静态数据成员:
- class Circle
- {
- private:
- //静态成员的声明,注意私有
- static double pi;
- private:
- double radius;
- public:
- Circle(double r = 0.0):pi(3.14),radius(r) {} //error
- Circle(double r = 0.0):radius(r) {} // ok;
- Circle(double r = 0.0):radius(r)
- {
- pi = 3.14; // ok; 但是没有必要
- }
- };
- //静态成员的定义
- double Circle::pi = 3.14;
总结:
同全局变量相比,使用静态数据成员有两个优势:
1、静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其他全局名字冲突的可能性。
2、可以实现信息隐藏,静态成员可以是private成员,而全局变量不能。
静态数据成员属于整个类型,使用时可用以下格式:
类名::静态数据成员名 或 对象.静态数据成员名(前提是可访问符为public)
示例:
用静态数据成员记录由同一类建立的对象的数量。
定义学生类,统计学生的信息:
- int m_count = 0;//1、全局变量
- //全局变量可以实现对象的共享,但是没有权限的限制,导致其他的函数或者对象可以无限制修改,则会出现问题(不安全)
- class Student
- {
- public:
- Student(int num = 0, const char* name = "", char sex = 'm'):m_num(num), m_sex(sex)
- {
- m_name = new char[strlen(name) + 1];
- strcpy_s(m_name, strlen(name) + 1, name);
- m_count++;
- }
- ~Student()
- {
- if (m_name != NULL)
- {
- delete[]m_name;
- m_name = NULL;
- }
- }
- void Print(){
- cout << "总数" << m_count << endl;
- }
- private:
- int m_num;
- char* m_name;
- char m_sex;
- static int m_count;//2、普通成员变量是本类某个对象独有的,类作用域,不能实现共享,外界修改不了(比较安全)
- };
- int Student::m_count;
- void main()
- {
- Student s(1001, "张三", 'm');
- Student s1(1003, "张三", 'w');
- Student s2(2005, "张三", 'm');
- s.Print();
- s1.Print();
- s2.Print();
- }
- class Cat // 猫
- {
- private:
- static int num;
- private:
- std::string _owner; //猫主
- std::string _name; //猫名
- public:
- Cat(const string &owner,
- const string &name):_owner(owner),_name(name)
- {
- num+=1;
- cout<<"create Cat num: "<< num<
- }
- ~Cat()
- {
- num-=1;
- cout<<"Destroy Cat num: "<
- }
- void print() const
- {
- cout<<"Owner: "<<_owner<<" Name: "<
- num+=1; // not this;
- }
- };
4、若类中含有静态成员,则该成员不在能本类中开辟空间,静态数据成员不占类的大小,不能在构造函数中初始化。
- class A
- {
- public:
- //A():m_a(1),m_b(2),m_c(3){}//m_c不能在构造函数中初始化
- A() :m_a(1), m_b(2)
- {
- //m_c = 3;//赋值, 没有给m_c开辟空间
- m_c++;
- }
- void Print()
- {
- cout << m_c << endl;
- }
- private:
- int m_a;//4
- char m_b;//1 1->4
- static int m_c;//m_c没有在A类开辟空间
- //引用性声明,仅用于声明
- };
- int A::m_c = 0;//定义性声明 开辟空间
- void main()
- {
- cout << sizeof(A) << endl;
- A a;
- a.Print();
- A b;
- b.Print();
- }
5、静态属性的类型是int,short,char,并且是const,可以在类中直接初始化
- class Bar
- {
- private:
- static const int nameSize = 20; // ok;
- static const char name[nameSize]="xiao cheng bar"; // error;
- };
6、静态数据成员的类型可以是其所属类,而非static数据成员只能被声明为该类的指针
- class Bar
- {
- private:
- std::string _name;
- private:
- static Bar sm_bar; // ok;
- private:
- Bar m_bar; // error;
- Bar *pb; // ok;
- };
总结:
1、设计静态数据成员目的是信息共享和信息交流
2、类的静态数据成员为所有类对象所共享,不属于某个具体的实例
3、类的静态数据成员必须在类外定义,定义时不添加static关键字,不能在构造函数的初始化列表中创建
4、类的静态数据成员类型是int,short,char,long long,并且是const,可以在类中直接初始化,也可以在类外初始化
5、在类的成员函数中使用静态数据成员,静态数据成员之前没有this
6、当类的静态数据成员为公有时,可以在外部函数使用:类名::静态数据成员名 或 对象.静态数据成员名,可以在类体中定义自身的静态类型对象
三、静态方法
函数成员说明为静态,将与该类的不同对象无关。静态函数成员的调用,在对象之外可以采用下面的方式:
类名::函数名 或 对象名.函数名
与静态数据成员相反,为使用方便,静态函数成员多为公有。
- class Object
- {
- private:
- static int num;
- private:
- int value;
- public:
- Object(int val = 0):value(val),num(val) {}// error;静态属性只能在类外初始化
- Object(int val):value(val)
- {
- num = 1; // 不是初始化,是赋值
- }
- void print()
- {
- cout<<"value: "<
" num: "< - }
- static void show() // 静态函数 not this
- {
- cout<<"value: "<
" num: "< - }
- static void fun(Object &obj) // const // 不能定义为常方法。
- {
- cout<
" "< - }
- };
- int Object::num = 0;
静态成员函数没有this指针,因此在静态成员函数显式地使用this指针都将导致编译时刻错误。试图访问隐式使用this指针所指向的非静态数据成员也会导致编译时刻错误。
- class Student
- {
- public:
- Student(int num = 0, const char* name = "", char sex = 'm') :m_num(num), m_sex(sex)
- //m_count(0),m_num(num),m_sex(sex)
- {
- m_name = new char[strlen(name) + 1];
- strcpy_s(m_name, strlen(name) + 1, name);
- m_count++;
- }
- ~Student()
- {
- if (m_name != NULL)
- {
- delete[]m_name;
- m_name = NULL;
- }
- }
- void Print() {
- cout << "总数" << m_count << endl;
- }
- //在static函数中,没有this指针,所以不能直接输出非静态数据成员
- static void Show(Student &s )
- {
- cout << "Show" << endl;
- cout << s.m_num << s.m_name << s.m_sex << m_count << endl;
- }
- private:
- int m_num;
- char* m_name;
- char m_sex;
- static int m_count;
- //const int m_j;//成员初始化列表
- //const static int m_i = 20;
- };
- int Student::m_count;
- void main()
- {
- Student s(1001, "张三", 'm');
- Student s1(1003, "张三", 'w');
- Student s2(2005, "张三", 'm');
- s.Print();
- s1.Print();
- s2.Print();
- s.Show(s);//没有this指针来接收,不管是用哪个对象来调用static,本质使用当前对象的类型Student来调用
- Student::Show(s2);//right,不用特别去声明成员调用此函数
- //Student::Print();//error,非静态只能用对象来调用,非static中,有this指针,必须通过对象来调用
- }
总结:
一个常规的成员函数声明描述了三件在逻辑上相互不同的事情:
- 该函数能访问类声明的私用部分。
- 该函数位于类的作用域之中。
- 该函数必须由一个对象去激活(有一个this指针)。
将一个函数声明为友元可以使它只具有第一种性质。
将一个函数声明为static可以使它只具有第一种和第二种性质。
-
相关阅读:
C#对字典容器Dictionary<TKey, TValue>内容进行XML序列化或反序列化报错解决方法
利用 Python PyPDF2库轻松提取PDF文本(及其他高级操作)
Machine learning week 5(Andrew Ng)
c++/c图的邻近矩阵表示
MSDC 4.3 接口规范(21)
文件加密系统是如何实现企业数据高效安全保护的?
Verilog task使用说明
【论文极速读】Prompt Tuning——一种高效的LLM模型下游任务适配方式
关于POM声明为provided的依赖,运行程序时报错NoClassDefFoundError
汽车油耗NEDC与WLTP有什么区别?以及MATLAB/Simulink的汽车行驶工况仿真
-
原文地址:https://blog.csdn.net/weixin_59179454/article/details/127759353