C++_静态成员

C语言中的Static(不涉及到类)

一句话描述C语言中static的作用:

无论是针对变量还是函数:static作用都是修改变量的作用域

静态成员的分类:

静态成员包括静态变量静态函数两部分

静态变量

静态全局变量

引入的原因(作用):隐藏变量(主要功能)

说明:即加了static,就会对其它源文件隐藏。

具体来说,如果直接定义全局变量,则该全局变量相当于一个项目变量,即是在整个项目的cpp中共享的,可以使用extern在别的cpp文件中使用。而如果定义成静态全局变量,该全局变量就变成了一个文件变量,即是在所在cpp文件使用。

优点:利用其隐藏特性,可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。

程序:

  1. #include <iostream>   
  2. using namespace std;  
  3.   
  4. static int a;  
  5.   
  6. void func1();  
  7.   
  8.   
  9. int  main()  
  10. {  
  11.     cout<<"a = "<<a<<endl;//输出静态变量的值:0   
  12.     int a = 1;  
  13.     cout<<"a = "<<a<<endl; //输出内部变量的值:1   
  14.     a = 10;  
  15.     cout<<"a = "<<a<<endl; //输出内部变量的值:10   
  16.     func1();       //输出静态变量的值:2   
  17.     cout<<"a = "<<a<<endl; //输出内部变量的值:10   
  18.     system("pause");  
  19. }  
  20.   
  21. void func1()  
  22. {  
  23.     a += 2;   
  24.     cout<<"a = "<<a<<endl; //2   
  25. }  
#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)统计访问所在函数的次数

举例:

  1. #include <iostream>   
  2. using namespace std;  
  3.   
  4. void func1();  
  5. void func2();  
  6.   
  7. int  main()  
  8. {  
  9.     int a = 0;  
  10.     cout<<"a = "<<a<<endl; //0   
  11.     func1();//4   
  12.     func1();//6   
  13.     cout<<"a = "<<a<<endl; //0   
  14.     func2();//4   
  15.     system("pause");  
  16. }  
  17.   
  18. void func1()  
  19. {  
  20.     static int a = 2;  
  21.     a += 2;   
  22.     cout<<"a = "<<a<<endl; //第一输出 4 第二次输出6   
  23. }  
  24.   
  25. void func2()  
  26. {  
  27.     static int a = 2;  
  28.     a += 2;   
  29.     cout<<"a = "<<a<<endl; //4   
  30. }  
#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

一句话描述C++语言中static的作用:

静态变量:让本类的所有对象都共享。静态函数:在对象出现前做些操作

注意:

类体中的成员的声明前加上static关键字,该成员就成为了该类的静态成员。和其他成员一样,静态成员也遵守public/protected/private访问规则。

静态数据成员

为什么要引入静态数据成员:主要原因是为了取代全局变量,让类的所有对象共享数据。

什么时候使用静态数据成员:定义类的各个对象公有的数据,如统计总数,平均数

优点:可以节省内存

类中的静态变量在内存中只存储一次,供所有对象所共有的,一旦一个对象改变其值,其他对象可以直接使用改变的值,这样可以提高效率和节省内存空间。

缺点:

由于静态变量时是类的多个对象共享。则在多线程的情况下,访问静态变量我们需要加一些异步机制,防止多个线程同时修改静态变量。

语法:

定义:static + 普通数据成员定义

初始化位置:必须在类外初始化,主函数前,而不能在类中进行初始化

注意:不能在类的初始化(在.h文件中)中对静态变量进行初始化,这样会导致重复定义

初始化方式:类型 类名::变量 = 值;------注意这时,前面不能加static

使用:

类外使用:

       访问规则:public

       使用方式:类对象名.静态数据成员名 或 类类型名::静态数据成员名

类中使用:

       访问规则:public/protected/private可以是任意方式定义)

       使用方式:直接使用静态成员名

举例:

  1. 静态成员的定义:static int x;  
  2. 静态成员初始化:int A::x=1;  
静态成员的定义:static int x;
静态成员初始化:int A::x=1;

性质:

1、针对类而言,只有一个静态数据存储空间 且 存储空间不由构造函数分配

2、类中的静态数据成员在编译时创建并初始化,在所有类的任何对象被建立前就存在。

3、静态数据成员的所有对象所共享,包括该类派生类的对象。即派生类对象与基类对象共享基类的静态数据成员。

举例:

  1. #include<iostream>   
  2. using namespace std;  
  3. class A  
  4. {  
  5. protected:  
  6.     static int num;  
  7. public:  
  8.     void show()  
  9.     {  
  10.         cout<<"num:"<<num<<endl;  
  11.     }  
  12. };  
  13. class B:public A  
  14. {  
  15. public:  
  16.     B()  
  17.     {  
  18.         num++;  
  19.     }  
  20.     void show()  
  21.     {  
  22.         cout<<"num:"<<num<<endl;  
  23.     }  
  24. };  
  25. int A::num=0;//静态数据成员的真正定义---写成 int B::num=0; 也是可以的   
  26. void main()  
  27. {  
  28.     A a;  
  29.     a.show();  
  30.     B b;  
  31.     b.show();  
  32.     B bb;  
  33.     bb.show();  
  34.     system("pause");  
  35. }  
#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、静态数据成员可以成为成员函数的确省参数,而普通数据成员则不可以

举例:

  1. #include<iostream>   
  2. using namespace std;  
  3. class A  
  4. {  
  5. protected:  
  6.     static int num;  
  7. public:  
  8.     void count(int i=num)//通常确省参数给出的是数,这里可以使用静态成员   
  9.     {  
  10.   
  11.     }  
  12. };  
  13. int A::num=0;  
  14. void main()  
  15. {  
  16.     A a;  
  17.     system("pause");  
  18. }  
#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、静态数据成员的类型可以是自己类的类型,而普通数据成员则不可以。普通数据成员的只能声明为 所属类类型的指针或引用。

举例:

  1. class A  
  2. {  
  3. protected:  
  4.     A aaa;//错误,普通数据成员不可以使用自己类作为类型名   
  5.     A *b; //正确,普通成员可以使用自己类的指针   
  6.     static A aa;//正确,静态成员函数可以使用自己类作为类型名   
  7. };  
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、静态成员函数不能是虚函数

举例:

  1. class   A  
  2. {     
  3.     virtual   static   void   a();//错误      
  4.     static   void   b()   const;//错误      
  5.     static   void   c()   volatile;//错误      
  6. };   
class   A
{   
	virtual   static   void   a();//错误   
	static   void   b()   const;//错误   
	static   void   c()   volatile;//错误   
}; 

举例:

  1. #include<iostream>   
  2. using namespace std;  
  3. class A  
  4. {  
  5. private:   
  6.     int i;  
  7.     static int j;  
  8. public:  
  9.     A(int i=1)  
  10.     {  
  11.         this->i=i;  
  12.     }  
  13.     static void show();  
  14.     void show(const A&a);  
  15. };  
  16. int A::j=0; //类外初始化静态变量时,不要加static   
  17. void A::show()//类外定义函数体时,不要加static ----静态函数访问静态成员   
  18. {  
  19.     cout<<j<<endl;  
  20. }  
  21. void A::show(const A&a)//静态函数访问非静态成员,必须加参数   
  22. {  
  23.     cout<<a.i<<endl;  
  24.     cout<<j<<endl;  
  25. }  
  26. void main()  
  27. {  
  28.     A a;  
  29.     a.show();  
  30.     a.show(a);  
  31.     system("pause");  
  32. }  
#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:

表示函数中的变量不可修改

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值