目录
省时间读这里:
开发中static是为了限制其作用域只在定义该变量或函数的源文件内有效,而在同一工程下的其他源文件中不能使用。
遇到的问题:
Q:头文件中定义了static变量或函数,只要引入该头文件,还是可以使用这些static修饰的变量或函数,为什么?
A:含了该头文件的所有源文件中都定义了这些变量,即该头文件被包含了多少次,这些变量就定义了多少次,导致实际上同名变量值却不同。
一.静态成员
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员,静态成员只能在当前源文件使用。
静态成员分为:
1.静态成员变量
-
所有对象共享同一份数据
-
在编译阶段分配内存
-
类内声明,类外初始化
#include <iostream>]
using namespace std;
class Person
{
public:
static int m_A; //静态成员变量
//静态成员变量特点:
//1 在编译阶段分配内存
//2 类内声明,类外初始化
//3 所有对象共享同一份数据
private:
static int m_B; //静态成员变量也是有访问权限的
};
//在类外初始化
int Person::m_A = 10;
int Person::m_B = 10;
void test01()
{
//静态成员变量两种访问方式
//1、通过对象
Person p1;
p1.m_A = 100;
cout << "p1.m_A = " << p1.m_A << endl;
Person p2;
p2.m_A = 200;
cout << "p1.m_A = " << p1.m_A << endl; //共享同一份数据
cout << "p2.m_A = " << p2.m_A << endl;
//2、通过类名
cout << "m_A = " << Person::m_A << endl;
//cout << "m_B = " << Person::m_B << endl; //私有权限访问不到
}
int main() {
test01();
system("pause");
return 0;
}
上面代码输出:
p1.m_A = 100
p1.m_A = 200
p2.m_A = 200
m_A = 200
2.静态成员函数
-
所有对象共享同一个函数
-
静态成员函数只能访问静态成员变量
#include <iostream>
using namespace std;
class Person
{
public:
//静态成员函数特点:
//1 程序共享一个函数
//2 静态成员函数只能访问静态成员变量
static void func()
{
cout << "func调用" << endl;
m_A = 100;
//m_B = 100; //错误,不可以访问非静态成员变量
}
static int m_A; //静态成员变量
int m_B; //
private:
//静态成员函数也是有访问权限的
static void func2()
{
cout << "func2调用" << endl;
}
};
int Person::m_A = 10;
void test01()
{
//静态成员变量两种访问方式
//1、通过对象
Person p1;
p1.func();
//2、通过类名
Person::func();
//Person::func2(); //私有权限访问不到
}
int main() {
test01();
system("pause");
return 0;
}
上面代码输出:
func调用
func调用
二.全局变量及函数和静态变量及函数
1.全局变量和函数
一般变量函数默认都为全局的。
全局变量及函数:在当前源文件以及其他源文件都可以使用,如果其他源文件使用需要extern对全局变量及函数进行声明。使用extern声明变量时不能带有初始值,否则仍然属于变量定义,会出现变量重定义的错误。
使用extern关键字
test.cpp
#include <iostream>
using namespace std;
// 定义为外部变量
extern int num = 100;
// 定义为外部函数
extern void fun() {
cout << "test.cpp - fun()" << endl;
}
main.cpp
// main.cpp
#include <iostream>
using namespace std;
extern void fun();
extern int num;
void test() {
fun(); // test.cpp - fun()
cout << num << endl; // 100
}
int main()
{
test();
system("pause");
return 0;
}
2.静态变量及函数
使用static关键字
加修饰的变量和函数。
静态成员只能在当前源文件使用,其他源文件不能使用,但是如果在头文件中声明并定义了static变量或函数,那么引入该头文件的源文件也可以使用static变量或函数,这时候就感觉和刚刚说的相违背,但其实定义全局变量时使用static,意味着该变量的作用域只限于定义它的源文件中,其它源文件不能访问。既然这种定义方式出现在头文件中,那么可以很自然地推测:包含了该头文件的所有源文件中都定义了这些变量,即该头文件被包含了多少次,这些变量就定义了多少次。
假如将上面两行代码的static去掉,编译的时候就会出现变量重定义的错误,这进一步证实了上面的推测,因为没有static的话变量的作用域是全局的,定义了两个以上的同名变量就会出现该错误。
所以,在头文件中定义static变量会造成变量多次定义,造成内存空间的浪费,而且也不是真正的全局变量。应该避免使用这种定义方式。
静态变量和函数具体分为以下几种:
在类外定义:
1、静态全局变量
使用:全局变量前加static,修饰全局变量为静态全局变量。
作用:改变全局变量的可见性。静态全局变量的存储位置在静态存储区,未被初始化的静态全局变量会被自动初始化为0。静态全局变量在声明它的文件之外是不可见的,仅在从定义该变量的开始位置到文件结尾可见。
2、静态局部变量
使用:局部变量前加static,修饰局部变量为静态局部变量。
作用:改变局部变量的销毁时期。静态局部变量的作用域和局部变量的作用域一样,当定义它的函数或语句块结束的时候,作用域结束。不同的是,静态局部变量存储在静态存储区,当静态局部变量离开作用域后,并没有被销毁。当该函数再次被调用的时候,该变量的值为上次函数调用结束时的值。
3、静态函数
使用:函数返回类型前加static,修饰函数为静态函数。
作用:改变函数的可见性。函数的定义和声明在默认情况下都是extern的,但静态函数只在声明它的文件中可见,不能被其他文件使用。
在类内定义:
最开始使用的案例代码都是在类中定义的类的静态成员变量和类的静态成员函数
4、类的静态成员变量
使用:类成员前加static,修饰类的成员为类的静态成员。
作用:实现多个对象之间的数据共享,并且使用静态成员不会破坏封装性,也保证了安全性。
class Person
{
public:
static int m_A; //静态成员变量
}
5、类的静态成员函数
使用:类函数前加static,修饰类的函数为静态函数。
作用:减少资源消耗,不需要实例化就可以使用。
class Person
{
public:
static void func()
{
cout << "func调用" << endl;
m_A = 100;
//m_B = 100; //错误,不可以访问非静态成员变量
}
}
三.为什么要用static
1.保护数据,做到数据隔离
根据上面使用全局变量的方法,全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,全局变量在所有的源文件中都是有效的。如果希望全局变量仅限于在本源文件中使用,在其他源文件中不能引用,也就是说限制其作用域只在定义该变量的源文件内有效,而在同一源程序的其他源文件中不能使用,这时,就可以通过在全局变量上加static来实现,使全局变量被定义成一个静态全局变量。这样就可以避免其他源文件使用该变量、避免其他源文件因为该变量引起的错误。
2.维持数据的持续性
静态变量和静态函数的生命周期是整个进程,存储在全局静态存储区,全局变量和静态变量的存储都放在这里, 有时候,我们希望函数中局部变量的值在函数调用结束之后不会消失,仍然保留函数调用结束的值。这时可以将该局部变量用关关键字static声明为静态局部变量。当局部变量被声明为静态局部变量的时候,也就改变了局部变量的存储位置,从原来的栈中存放改为静态存储区存放,全局变量也存放在静态存储区。静态局部变量与全局变量的主要区别就在于可见性,静态局部变量只在其被声明的代码块中是可见的。