由关键字static修饰类体中成员,成为类静态成员(static class member)。类的静态成员为其所有对象共享,不管有多少对象,静态成员只有一份存于公用内存中。静态数据成员被当作该类类型的全局对象对.
在类设计中,用关键字static修饰的数据成员为静态数据成员。有该类型实例化的所有对象,共享系统为静态成员分配的一个存储空间,而这个存储空间是程序执行main函数之前分配的,在实例化对象时不再为静态成员分配空间(静态成员数据不在对象空间中)。
对于一个类:定义学生类,统计学生的信息。
如下函数,想要对类内的某个成员变量进行统计改变,每新定义一个新的类,每个类中的这个普通成员变量希望其能一起改变:
设计静态数据成员目的是信息共享
普通成员变量是本类某个对象独有的,类作用域,不能实现共享,外界修改不了(比较安全)
但普通的成员变量无法实现,
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();
}
运行结果:

全局变量可以实现对象的共享,但是没有权限的限制,导致其他的函数或者对象可以无限制修改,则会出现问题(不安全)
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();
}
运行结果:

静态局部变量:程序运行结束才销毁
//静态局部变量:程序运行结束才销毁
#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.类的声明文件 – 为.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();
}

同全局变量相比,使用静态数据成员有两个优势:
1)静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其他全局名字冲突的可能性。
2)可以实现信息隐藏,静态成员可以是private成员,而全局变量不能,
3)静态数据是该类所有对象所共有的,可提供同一类型的所有对象之间,信息共享或信息交换的一种方式。
静态数据成员属于整个类型,使用时可用以下格式:
类名:静态数据成员名或对象.静态数据成员名(前提是可访问符为public)
1、设计静态数据成员目的是信息共享和信息交流
2、类的静态数据成员为所有类对象所共享,不属于某个具体的实例。
3、类的静态数据成员必须在类外定义,定义时不添加static关键字,不能在构造函数的初始化列表中创建。
4、类的静态数据成员类型是int,short, char , long long ,并且是const ,可以在类中直接初始化,也可以在类外初始化。
(但是个人觉得这种写法不太好,如果{}还没结束的话,这个类是还没定义好的,类如果还没定义好,是不能用这个类去定义对象,那既然没有定义对象,那我们就不能为其开辟空间,那如果没有为其开辟空间,那怎么赋值呢)
5、在类的成员函数中使用静态数抵成员。静态数据成员之前没有this。
6、当类的静态数据成员为公有时,可以在外部函数使用:类名::静态数据成员名或对象。静态数据成员名。可以在类体中定义自身的静态类型对象。
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指针,必须通过对象调用
}
运行结果:

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