C语言中的Static(不涉及到类)
一句话描述C语言中static的作用:
静态成员的分类:
静态成员包括静态变量和静态函数两部分
静态变量
静态全局变量
引入的原因(作用):隐藏变量(主要功能)
说明:即加了static,就会对其它源文件隐藏。
具体来说,如果直接定义全局变量,则该全局变量相当于一个项目变量,即是在整个项目的cpp中共享的,可以使用extern在别的cpp文件中使用。而如果定义成静态全局变量,该全局变量就变成了一个文件变量,即是在所在cpp文件使用。
优点:利用其隐藏特性,可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。
- #include <iostream>
- using namespace std;
- static int a;
- void func1();
- int main()
- {
- cout<<"a = "<<a<<endl;//输出静态变量的值:0
- int a = 1;
- cout<<"a = "<<a<<endl; //输出内部变量的值:1
- a = 10;
- cout<<"a = "<<a<<endl; //输出内部变量的值:10
- func1(); //输出静态变量的值:2
- cout<<"a = "<<a<<endl; //输出内部变量的值:10
- system("pause");
- }
- void func1()
- {
- a += 2;
- cout<<"a = "<<a<<endl; //2
- }
#include <iostream>
using namespace std;
static int a;
void func1();
int main()
{
cout<<"a = "<<a<<endl;//输出静态变量的值:0
int a = 1;
cout<<"a = "<<a<<endl; //输出内部变量的值:1
a = 10;
cout<<"a = "<<a<<endl; //输出内部变量的值:10
func1(); //输出静态变量的值:2
cout<<"a = "<<a<<endl; //输出内部变量的值:10
system("pause");
}
void func1()
{
a += 2;
cout<<"a = "<<a<<endl; //2
}
定义:在全局变量前加上关键字static
特点:
(1)内存所在位置:静态存储区(即全局数据区)
(2)作用域:变量所在文件,(其他文件不可见)
(3)生命期:整个程序
(4)只在声明处初始化一次,不存在其他位置的初始化
(5)默认的初始化值为0,(局部变量默认值为随机值,全局变量默认值为0)
静态局部变量
定义:在局部变量(函数中的变量)前加上关键字static
特点:
(1)内存所在位置:静态存储区(即全局数据区)
(2)作用域:所在函数
(3)生命期:整个程序,程序结束,生命结束
(4)在函数调用时,才对其初始化,而且只在声明处初始化一次,其他位置初始化忽略不见(函数可能被调用多次)
(5)默认的初始化值为0,(局部变量默认值为随机值,全局变量默认值为0)
作用:
(1)判断函数是否被调用过
(2)统计访问所在函数的次数
举例:
- #include <iostream>
- using namespace std;
- void func1();
- void func2();
- int main()
- {
- int a = 0;
- cout<<"a = "<<a<<endl; //0
- func1();//4
- func1();//6
- cout<<"a = "<<a<<endl; //0
- func2();//4
- system("pause");
- }
- void func1()
- {
- static int a = 2;
- a += 2;
- cout<<"a = "<<a<<endl; //第一输出 4 第二次输出6
- }
- void func2()
- {
- static int a = 2;
- a += 2;
- cout<<"a = "<<a<<endl; //4
- }
#include <iostream>
using namespace std;
void func1();
void func2();
int main()
{
int a = 0;
cout<<"a = "<<a<<endl; //0
func1();//4
func1();//6
cout<<"a = "<<a<<endl; //0
func2();//4
system("pause");
}
void func1()
{
static int a = 2;
a += 2;
cout<<"a = "<<a<<endl; //第一输出 4 第二次输出6
}
void func2()
{
static int a = 2;
a += 2;
cout<<"a = "<<a<<endl; //4
}
例子说明:
(1)main函数中的a和func1、func2函数中的a空间位置不同,其值的改变会不影响
(2)func1被调用了两次,但是在第二次调用输出后结果为6,原因是第二次静态变量a的初始化被忽视,而在直接执行操作
(3)func1和func2中都存在静态变量a,但是它们的空间位置也是不同的,所以值的改变也互不影响
注意
(1)静态局部变量与局部变量的对比
函数中的局部变量作用域是所在函数,而且在多次函数调用时,会产生多个副本。
函数的静态局部变量作用域也是所在函数,但是在多次调用函数时,只产生一个副本。
说白了就是,静态局部变量可以使用多次,而且下次使用的时候依旧可以使用上次的值,而局部变量只能使用一次,每次使用的都是新值。
(2)全局变量和全局静态变量的区别
相同点:都是在静态存储区分配空间
不同点:作用域不同
具体来说,全局变量可以在整个工程使用,即在一个文件内定义的全局变量,在另一个文件中,通过extern 全局变量名的声明,就可以使用全局变量。但是静态全局变量只能在一个cpp中使用。
(3)从分配内存空间上对比(静态局部变量、局部变量、全局变量、静态全局变量)
全局变量、静态局部变量、静态全局变量都在静态存储区分配空间,而局部变量在栈分配空间
说明
1、若全局变量仅在单个文件中访问,则可以将这个变量修改为静态全局变量。
2、若全局变量仅在单个函数中使用 而且 下次函数的调用需要使用上一次的值,则可以将这个变量变成该函数的静态局部变量。
3、全局变量、静态局部变量、静态全局变量都存放在静态数据存储区。
静态函数
引入的原因:限定函数的作用域,让其只能在所在文件可见,不能被其它文件使用。
优点:静态函数不能被其它文件所用,在其它文件中可以定义相同名字的函数,不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名,即使同名不会发生冲突。
定义:static + 正常函数定义
说明:
1、静态函数与普通函数的对比
区别:
(1)作用域不同。
静态函数只能在声明它的文件当中可见,不能被其它文件使用。普通函数可以再其他文件中使用
(2)在内存中存放不同
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
相同点:除了上述的两个不同点外,静态函数可以看出普通的函数。
静态函数可以调用普通函数,普通函数也可以调用静态函数。
面向对象的static
静态变量:让本类的所有对象都共享。静态函数:在对象出现前做些操作
注意:
类体中的成员的声明前加上static关键字,该成员就成为了该类的静态成员。和其他成员一样,静态成员也遵守public/protected/private访问规则。
静态数据成员
为什么要引入静态数据成员:主要原因是为了取代全局变量,让类的所有对象共享数据。
什么时候使用静态数据成员:定义类的各个对象公有的数据,如统计总数,平均数
优点:可以节省内存
类中的静态变量在内存中只存储一次,供所有对象所共有的,一旦一个对象改变其值,其他对象可以直接使用改变的值,这样可以提高效率和节省内存空间。
缺点:
由于静态变量时是类的多个对象共享。则在多线程的情况下,访问静态变量我们需要加一些异步机制,防止多个线程同时修改静态变量。
语法:
定义:static + 普通数据成员定义
初始化位置:必须在类外初始化,主函数前,而不能在类中进行初始化
注意:不能在类的初始化(在.h文件中)中对静态变量进行初始化,这样会导致重复定义
初始化方式:类型 类名::变量 = 值;------注意这时,前面不能加static
使用:
类外使用:
访问规则:public
使用方式:类对象名.静态数据成员名 或 类类型名::静态数据成员名
类中使用:
访问规则:public/protected/private(可以是任意方式定义)
使用方式:直接使用静态成员名
举例:
- 静态成员的定义:static int x;
- 静态成员初始化:int A::x=1;
静态成员的定义:static int x;
静态成员初始化:int A::x=1;
性质:
1、针对类而言,只有一个静态数据存储空间 且 存储空间不由构造函数分配
2、类中的静态数据成员在编译时创建并初始化,在所有类的任何对象被建立前就存在。
3、静态数据成员被类的所有对象所共享,包括该类派生类的对象。即派生类对象与基类对象共享基类的静态数据成员。
举例:
- #include<iostream>
- using namespace std;
- class A
- {
- protected:
- static int num;
- public:
- void show()
- {
- cout<<"num:"<<num<<endl;
- }
- };
- class B:public A
- {
- public:
- B()
- {
- num++;
- }
- void show()
- {
- cout<<"num:"<<num<<endl;
- }
- };
- int A::num=0;//静态数据成员的真正定义---写成 int B::num=0; 也是可以的
- void main()
- {
- A a;
- a.show();
- B b;
- b.show();
- B bb;
- bb.show();
- system("pause");
- }
#include<iostream>
using namespace std;
class A
{
protected:
static int num;
public:
void show()
{
cout<<"num:"<<num<<endl;
}
};
class B:public A
{
public:
B()
{
num++;
}
void show()
{
cout<<"num:"<<num<<endl;
}
};
int A::num=0;//静态数据成员的真正定义---写成 int B::num=0; 也是可以的
void main()
{
A a;
a.show();
B b;
b.show();
B bb;
bb.show();
system("pause");
}
4、静态数据成员可以成为成员函数的确省参数,而普通数据成员则不可以
举例:
- #include<iostream>
- using namespace std;
- class A
- {
- protected:
- static int num;
- public:
- void count(int i=num)//通常确省参数给出的是数,这里可以使用静态成员
- {
- }
- };
- int A::num=0;
- void main()
- {
- A a;
- system("pause");
- }
#include<iostream>
using namespace std;
class A
{
protected:
static int num;
public:
void count(int i=num)//通常确省参数给出的是数,这里可以使用静态成员
{
}
};
int A::num=0;
void main()
{
A a;
system("pause");
}
5、静态数据成员的类型可以是自己类的类型,而普通数据成员则不可以。普通数据成员的只能声明为 所属类类型的指针或引用。
举例:
- class A
- {
- protected:
- A aaa;//错误,普通数据成员不可以使用自己类作为类型名
- A *b; //正确,普通成员可以使用自己类的指针
- static A aa;//正确,静态成员函数可以使用自己类作为类型名
- };
class A
{
protected:
A aaa;//错误,普通数据成员不可以使用自己类作为类型名
A *b; //正确,普通成员可以使用自己类的指针
static A aa;//正确,静态成员函数可以使用自己类作为类型名
};
注意:
1、类中静态成员变量 和 类中非静态成员变量的对比
(1) 对象是否拥有
对于非静态数据成员,每个类对象都有自己的拷贝,都拥有一份自己的变量。
对于静态数据成员,静态数据成员是该类的所有对象所共有的。即无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷 贝,只分配一次内存,由该类型的所有对象共享访问。
(2) 内存的分配
静态数据成员存储在全局数据区。不能在类声明中定义。
内部成员(非全局,非静态,非const变量)存储在栈中。
2、类中静态成员变量与全局变量相比
(1) 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
(2 )可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;
静态成员函数
为什么要引入静态数据成员:主要原因是为了取代全局函数,能在调用构造函数前(未初始化类之前)调用,通常CALLBACK函数中会用得到。
什么时候使用静态数据成员:
(1) 为了访问全局变量或类的静态数据成员
(2) 要调用一个函数,该函数是在构造对象之前使用,但是不能使用全局函数(不符合OO实现),而且类中非静态函数的调用需要使用对象,这时候需要使用静态成员函数。
语法:
定义:static + 普通成员函数定义
定义位置:可以在类内,也可以自类外。类外定义是不加static
使用:
类外使用:
访问规则:public
使用方式:类名::静态公有成员函数名(实参表);
注意:和普通的成员变量一样,如果是私有或受保护的,不能在类外直接使用
类中使用:
访问规则:public/protected/private(可以是任意方式定义)
使用方式:直接使用静态成员函数
性质:
1、没有this指针,不可以直接访问类中非非静态成员函数,常常用于访问类的静态数据和静态成员函数。
2、只属于一个类,可以再多个对象间共享。
3、一般情况下,静态成员函数不访问非静态成员函数,如果确实需要,则需要传入参数通过对象名访问。
4、静态成员函数不可以同时声明为virtual、const、volatile函数。
5、静态成员函数不能是虚函数
举例:
- class A
- {
- virtual static void a();//错误
- static void b() const;//错误
- static void c() volatile;//错误
- };
class A
{
virtual static void a();//错误
static void b() const;//错误
static void c() volatile;//错误
};
举例:
- #include<iostream>
- using namespace std;
- class A
- {
- private:
- int i;
- static int j;
- public:
- A(int i=1)
- {
- this->i=i;
- }
- static void show();
- void show(const A&a);
- };
- int A::j=0; //类外初始化静态变量时,不要加static
- void A::show()//类外定义函数体时,不要加static ----静态函数访问静态成员
- {
- cout<<j<<endl;
- }
- void A::show(const A&a)//静态函数访问非静态成员,必须加参数
- {
- cout<<a.i<<endl;
- cout<<j<<endl;
- }
- void main()
- {
- A a;
- a.show();
- a.show(a);
- system("pause");
- }
#include<iostream>
using namespace std;
class A
{
private:
int i;
static int j;
public:
A(int i=1)
{
this->i=i;
}
static void show();
void show(const A&a);
};
int A::j=0; //类外初始化静态变量时,不要加static
void A::show()//类外定义函数体时,不要加static ----静态函数访问静态成员
{
cout<<j<<endl;
}
void A::show(const A&a)//静态函数访问非静态成员,必须加参数
{
cout<<a.i<<endl;
cout<<j<<endl;
}
void main()
{
A a;
a.show();
a.show(a);
system("pause");
}
注意:
1、类的静态成员函数不能访问非静态成员,但是非静态成员可以访问静态成员。
2、出现在类体外的函数定义不能指定关键字static;
3、静态成员之间可以相互访问,即静态成员函数访问静态数据成员和访问静态成员函数;
4、非静态成员函数可以任意地访问静态成员函数和静态数据成员;
5、静态成员函数不能访问非静态成员函数和非静态数据成员;
6、调用静态成员函数,可以用对象调用,也可以通过类调用
说明:
1、static与const的对比
变量的对比:
static:是为限定变量的作用域的,值是可以改变的
const:是表示变量是常量,是不可变的,提高程序健壮性。
函数的对比:
static:
修饰C中的函数:是为了限定作用域仅在本文件,其他文件不可用
修饰C++中的函数:是为了在对象创建之前做一些操作
const:
表示函数中的变量不可修改