一、C语言中static的作用
1、隐藏变量或函数。被static修饰的变量或者函数,对其他文件是不可见的
static_a.cpp
static int a = 10;
int func()
{
return 5;
}
staitc_b.cpp
#include <iostream>
extern int func();
extern int a;
int main(void)
{
std::cout << func() << std::endl;
std::cout << a << std::endl;
return 0;
}
Makefile
object = static_a.o static_b.o
main : $(object)
g++ -g -o main $(object)
static_a.o : static_a.cpp
g++ -g -c static_a.cpp
static_b.o : static_b.cpp
g++ -g -c static_b.cpp
clean:
rm -rf *.o
rm -rf main
运行Makefile,提示:
也就是说对于static_b.cpp文件来说,static_a.cpp中的a是不可见的,因为static关键字隐藏了它。
2、保持变量生命周期直到整个程序执行结束才结束
一般情况下,局部变量会被存储在栈区,栈区的内存会在离开该语句块时由系统自动回收。但static修饰的变量却会被存储在内存布局的.data区段,该段内存中的变量值会在整个程序运行期间保持。
#include <iostream>
int func()
{
static int a = 3;
return a--;
}
int main(void)
{
std::cout << func() << std::endl;
std::cout << func() << std::endl;
return 0;
}
即func()函数的中的static变量a的值一直在保存着。第一次调用时是3,然后再次调用时并没有再次将a初始化为3,而是上次的2。
3、static修饰的变量未初始化时,会被编译器自动初始化为0
因为static修饰的变量像全局变量一样,当未初始化时,会被存放在.bss内存区段,而不是.data区域,.bss内存区域的变量会在程序执行前被自动初始化为0(详见实例分析C++内存布局),.bss段的内存中的内容具体是在编译时进行的0填充还是运行时不用管,总之是在程序运行前。
#include <iostream>
using namespace std;
static int a;
int b;
int main(void)
{
static int c;
int d;
cout << "a:" << a << endl;
cout << "b:" << b << endl;
cout << "c:" << c << endl;
cout << "d:" << d << endl;
return 0;
}
二、C++中static的作用
由于类的静态数据成员要在程序一开始运行时就已经存在,但函数却是在程序运行过程中被调用,所以类的静态数据成员不能在任何函数内分配空间和初始化,当然可以在类中声明,而定义放在类外。因为类的声明只是声明一个类的“尺寸和规格”,而并不进行实际的内存分配,所以只能在类的内部声明,并在类的外部定义并初始化(当然可以在类内直接声明成const类型并初始化)。
已经定义的静态数据成员引用方式为:<类名>::<静态成员员>
1、static修饰类中的成员函数或变量时,类的所有对象及类本身共用该成员变量或成员函数
类的所有实例共用静态数据成员(包括成员变量和成员函数)。类的静态变量和静态函数可以直接被类引用,而不需要类对象来引用。注意类中使用static声明的变量,只是进行了声明,并没有定义,需要在类的外部(也必须是其他任何函数函数的外部进行定义)定义,或者在类的内部定义成const类型的常量。
#include <iostream>
class A {
public:
static int a; //声明静态数据成员a
const static int c = 3; //在类中声明并定义const static类型的变量(其实是常量)
static void func(int i)
{
static int b = 100;
std::cout << "a = " << i << std::endl;
std::cout << "b = " << b++ << std::endl;
}
};
int A::a = 5; //必须在类外部及main函数外部进行定义并初始化
int main(void)
{
std::cout << "A::c = " << A::c << std::endl;
A::func(A::a);
A obj_a, obj_b;
A::a = 7;
obj_a.func(obj_a.a);
obj_a.a = 9;
obj_b.func(obj_b.a);
return 0;
}
根据a和b的输出结果可见类的所有对象及类本身共有静态成员变量和静态成员函数,且类可以直接引用静态成员函数和静态成员变量。
说明:类的静态成员注意事项
1.类的静态成员函数属于整个类而非类的对象,所以它没有this指针,这就导致它仅能访问类的静态数据和静态成员函数。
2.不能将静态成员函数定义为虚函数
3.静态常量声明只可以是整型,即static const类型的成员变量只能是整型,或者使用constexpr来定义常量表达式,具体参看:类的静态常量
class Ba {
public:
const static int a = 1;
constexpr static double b = 2.0;
}