• C++11 --- 浅谈静态成员


    一、静态成员

    由关键字static修饰类体中成员,成为类静态成员(static class member)。类的静态成员为其所有对象共享,不管有多少对象,静态成员只有一份存于公用内存中。静态数据成员被当作该类类型的全局对象对.

    静态属性

    在类设计中,用关键字static修饰的数据成员为静态数据成员。有该类型实例化的所有对象,共享系统为静态成员分配的一个存储空间,而这个存储空间是程序执行main函数之前分配的,在实例化对象时不再为静态成员分配空间(静态成员数据不在对象空间中)。

    二、静态数据成员

    1、为什么需要静态数据成员:

    对于一个类:定义学生类,统计学生的信息。
    如下函数,想要对类内的某个成员变量进行统计改变,每新定义一个新的类,每个类中的这个普通成员变量希望其能一起改变:

    设计静态数据成员目的是信息共享
    
    • 1

    1)普通成员变量不能实现

    普通成员变量是本类某个对象独有的,类作用域,不能实现共享,外界修改不了(比较安全)
    但普通的成员变量无法实现,

    
    class Student
    {
    public:
    	Student(int num = 0, const char* name = "", char sex = 'm') :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;
    	}
    private:
    	int m_num;
    	char* m_name;
    	char m_sex;
    	int m_count;
    };
    void main()
    {
    	Student s(1001, "张三", 'm');
    	Student s1(1003, "李四", 'm');
    	Student s2(2005, "小红", 'f');
    	s.Print();
    	s2.Print();
    	s1.Print();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    运行结果:
    在这里插入图片描述

    2)全局变量–可以实现对象的共享,但是没有权限的限制

    全局变量可以实现对象的共享,但是没有权限的限制,导致其他的函数或者对象可以无限制修改,则会出现问题(不安全)

    int m_count = 0;
    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;
    };
    void Test()
    {
    	m_count = 10;
    }
    void fn()
    {
    	m_count = 20;
    }
    void main()
    {
    	Student s(1001, "张三", 'm');
    	Student s1(1003, "李四", 'm');
    	s1.Print();
    	Student s2(2005, "小红", 'f');
    	s.Print();
    	Test();
    	s2.Print();
    	fn();
    	s1.Print();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    运行结果:

    在这里插入图片描述

    3)静态局部变量

    静态局部变量:程序运行结束才销毁

    //静态局部变量:程序运行结束才销毁
    #if 1
    void fn()
    {
    	int a = 0;
    	static int b = 0;//第一次遇到b进行初始化
    	a++;
    	b++;
    	cout << "a =" << a << "b= " << b << endl;
    }
    void main()
    {
    	for(int i = 0;i<5;i++)
    		fn();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4)类中的局部变量 -实现了本类对象的共享,又实现了限制(类作用域)

    类中的局部变量大小,不占类的大小

    静态数据成员的空间开辟?

    1.类的声明文件 – 为.h文件,可以被其他人不断的重复去使用,会导致空间的不停的开辟,所以不行
    2)类的成员函数的定义文件
    3)测试文件 – 不能修改其中的

    简单尝试使用:
    class A
    {
    public:
    	//A() :m_a(1), m_b(2), m_c(3) {}  //m_c不能在构造函数中初始化
    	A() :m_a(1), m_b(2)
    	{
    		m_c++;  //赋值
    	}
    	void print()
    	{
    		cout << m_c << endl;
    	}
    private:
    	int m_a;
    	char m_b;
        static int m_c;   //引用性声明
    };
    int A::m_c = 0; //定义性声明 开辟空间
    void test()
    {
    	//cout << m_c << endl;
    }
    
    void main()
    {
    	cout << sizeof(A) << endl;//8字节大小,类中的局部变量大小,不占类的大小
    	A a;
    	A b;
    	a.print();
    	b.print();
    	//cout << A::m_c << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    运行结果:

    在这里插入图片描述
    可以发现:
    静态数据成员 实现了本类对象的共享,又实现了限制(类作用域)

    使用示例:
    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;
    };
    int Student::m_count;
    void main()
    {
    	Student s(1001, "张三", 'm');
    	Student s1(1003, "李四", 'm');
    	Student s2(2005, "小红", 'f');
    	s.Print();
    	s2.Print();
    	s1.Print();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    运行结果:

    在这里插入图片描述

    2、总结

    同全局变量相比,使用静态数据成员有两个优势:

    1)静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其他全局名字冲突的可能性。
    2)可以实现信息隐藏,静态成员可以是private成员,而全局变量不能,
    
    3)静态数据是该类所有对象所共有的,可提供同一类型的所有对象之间,信息共享或信息交换的一种方式。
    
    • 1
    • 2
    • 3
    • 4

    静态数据成员属于整个类型,使用时可用以下格式:
    类名:静态数据成员名或对象.静态数据成员名(前提是可访问符为public)

    二、总结:

    1、设计静态数据成员目的是信息共享和信息交流
    2、类的静态数据成员为所有类对象所共享,不属于某个具体的实例。
    3、类的静态数据成员必须在类外定义,定义时不添加static关键字,不能在构造函数的初始化列表中创建。
    4、类的静态数据成员类型是int,short, char , long long ,并且是const ,可以在类中直接初始化,也可以在类外初始化。
    (但是个人觉得这种写法不太好,如果{}还没结束的话,这个类是还没定义好的,类如果还没定义好,是不能用这个类去定义对象,那既然没有定义对象,那我们就不能为其开辟空间,那如果没有为其开辟空间,那怎么赋值呢)
    5、在类的成员函数中使用静态数抵成员。静态数据成员之前没有this。
    6、当类的静态数据成员为公有时,可以在外部函数使用:类名::静态数据成员名或对象。静态数据成员名。可以在类体中定义自身的静态类型对象。

    示例代码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_num<<" "<<m_name<<" "<<m_sex<<" "<<"总数:" << m_count << endl;
    	}
    	//在static函数中,没有this,所以不能直接输出非static数据成员
    	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, "李四", 'm');
    	Student s2(2005, "小红", 'f');
    	s.Print();
    	s2.Print();
    	s1.Print();
    	s.Show(s);  //不管用哪个对象调用static,其实用的是当前对象的类型
    	Student::Show(s2);//不用特别声明对象调用此函数
    	//Student::Print(); //非static中,有this指针,必须通过对象调用
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    运行结果:

    在这里插入图片描述

    2、测试代码:

    class A
    {
    public:
    	A(){cout << "A" << endl;}
    	~A(){cout << "~A" << endl;}
    };
    void test()
    {
    	static A a;
    }
    void main()
    {
    	cout << "main begin" << endl;
    	for(int i = 0;i < 5;i++)
    		test();
    	cout << "main end" <<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行结果:

    在这里插入图片描述

  • 相关阅读:
    前端和后端是Web开发中的两个不同的领域,你更倾向于哪一种?
    scratch大鱼吃小鱼 电子学会图形化编程scratch等级考试二级真题和答案解析2022年6月
    【导航】嵌入式 Linux 学习专栏目录 【快速跳转】
    zlMediaKit 11 rtsp相关--分包/sdp信令交互/排序
    MySQL学习系列(10)-每天学习10个知识
    虚拟环境中使用的Python不是当前虚拟环境的,解决方法
    STM32 DMA学习
    【设计模式】职责链模式
    OPENCV实现DNN图像分类
    spacy教程(持续更新ing...)
  • 原文地址:https://blog.csdn.net/kyrie_sakura/article/details/127835265