C++11 --- 静态成员

本文深入探讨了C++中类的静态成员,包括静态属性和静态数据成员。静态成员使得类的所有对象共享同一份存储空间,用于实现信息共享。文章通过实例展示了静态成员在统计学生数量、避免全局变量冲突和限制访问等方面的优势,并强调了静态数据成员的类作用域和外部定义的必要性。同时,提到了静态成员函数的使用特点,如无this指针以及如何在类外初始化和访问静态成员。
摘要由CSDN通过智能技术生成

一、静态成员

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

静态属性

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

二、静态数据成员

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

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

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

运行结果:

在这里插入图片描述

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

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;
}
运行结果:

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

使用示例:
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();
}
运行结果:

在这里插入图片描述

2、总结

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

1)静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其他全局名字冲突的可能性。
2)可以实现信息隐藏,静态成员可以是private成员,而全局变量不能,

3)静态数据是该类所有对象所共有的,可提供同一类型的所有对象之间,信息共享或信息交换的一种方式。

静态数据成员属于整个类型,使用时可用以下格式:
类名:静态数据成员名或对象.静态数据成员名(前提是可访问符为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指针,必须通过对象调用
}

运行结果:

在这里插入图片描述

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;
}

运行结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值