c++中 static关键字

C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static。前者应用于普通变量和函数,不涉及类;后者主要说明static在类中的作用。

一、面向过程设计中的static

1、静态全局变量

在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。我们先举一个静态全局变量的例子,如下:

//Example 1
#include <iostream.h>
void fn();
static int n; //定义静态全局变量
void main()
{
	n=20;
	cout<<n<<endl;
	fn();
}

void fn()
{
	n++;
	cout<<n<<endl;
}

静态全局变量有以下特点:

  • 该变量在全局数据区分配内存;
  • 未经初始化的静态全局变量会被程序自动初始化为0(自动变量的值是随机的,除非它被显式初始化);
  • 静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的; 

静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。对于一个完整的程序,在内存中的分布情况如下图:

代码区
全局数据区
堆区
栈区

  一般程序的由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。细心的读者可能会发现,Example 1中的代码中将

	static int n; //定义静态全局变量

改为

	int n; //定义全局变量

程序照样正常运行。
的确,定义全局变量就可以实现变量在文件中的共享,但定义静态全局变量还有以下好处:

  • 静态全局变量不能被其它文件所用;
  • 其它文件中可以定义相同名字的变量,不会发生冲突;

您可以将上述示例代码改为如下:

//Example 2
//File1
#include <iostream.h>
void fn();
static int n; //定义静态全局变量
void main()
{
	n=20;
	cout<<n<<endl;
	fn();
}

//File2
#include <iostream.h>
extern int n;
void fn()
{
	n++;
	cout<<n<<endl;
}

编译并运行Example 2,您就会发现上述代码可以分别通过编译,但运行时出现错误。试着将

static int n; //定义静态全局变量

改为

int n; //定义全局变量

再次编译运行程序,细心体会全局变量和静态全局变量的区别。

2、静态局部变量

在局部变量前,加上关键字static,该变量就被定义成为一个静态局部变量。

我们先举一个静态局部变量的例子,如下:

//Example 3
#include <iostream.h>
void fn();
void main()
{
	fn();
	fn();
	fn();
}
void fn()
{
	static n=10;
	cout<<n<<endl;
	n++;
}

  通常,在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。
  但有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来,变量已经不再属于函数本身了,不再仅受函数的控制,给程序的维护带来不便。
  静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。

静态局部变量有以下特点:

  • 该变量在全局数据区分配内存;
  • 静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
  • 静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;
  • 它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;

3、静态函数

  在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。

静态函数的例子:

//Example 4
#include <iostream.h>
static void fn();//声明静态函数
void main()
{
	fn();
}
void fn()//定义静态函数
{
	int n=10;
	cout<<n<<endl;
}

定义静态函数的好处:

  • 静态函数不能被其它文件所用;
  • 其它文件中可以定义相同名字的函数,不会发生冲突;

二、面向对象的static关键字(类中的static关键字)

1、静态数据成员

在类内数据成员的声明前加上关键字static,该数据成员就是类内的静态数据成员。先举一个静态数据成员的例子。

//Example 5
#include <iostream.h>
class Myclass
{
public:
	Myclass(int a,int b,int c);
	void GetSum();
private:
	int a,b,c;
	static int Sum;//声明静态数据成员
};
int Myclass::Sum=0;//定义并初始化静态数据成员

Myclass::Myclass(int a,int b,int c)
{
	this->a=a;
	this->b=b;
	this->c=c;
	Sum+=a+b+c;
}

void Myclass::GetSum()
{
	cout<<"Sum="<<Sum<<endl;
}

void main()
{
	Myclass M(1,2,3);
	M.GetSum();
	Myclass N(4,5,6);
	N.GetSum();
	M.GetSum();

}

可以看出,静态数据成员有以下特点:

  • 对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;
  • 静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。在Example 5中,语句int Myclass::Sum=0;是定义静态数据成员;
  • 静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
  • 因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;
  • 静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:
    <数据类型><类名>::<静态数据成员名>=<值>
  • 类的静态数据成员有两种访问形式:
    <类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
    如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员 ;
  • 静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。所以,应该把利息设为存款类的静态数据成员。这有两个好处,第一,不管定义多少个存款类对象,利息数据成员都共享分配在全局数据区的内存,所以节省存储空间。第二,一旦利息需要改变时,只要改变一次,则所有存款类对象的利息全改变过来了;
  • 同全局变量相比,使用静态数据成员有两个优势:
  1. 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
  2. 可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;

2、静态成员函数

  与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分。普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this 是缺省的。如函数fn()实际上是this->fn()。但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。下面举个静态成员函数的例子。

//Example 6
#include <iostream.h>
class Myclass
{
public:
	Myclass(int a,int b,int c);
	static void GetSum();/声明静态成员函数
private:
	int a,b,c;
	static int Sum;//声明静态数据成员
};
int Myclass::Sum=0;//定义并初始化静态数据成员

Myclass::Myclass(int a,int b,int c)
{
	this->a=a;
	this->b=b;
	this->c=c;
	Sum+=a+b+c; //非静态成员函数可以访问静态数据成员
}

void Myclass::GetSum() //静态成员函数的实现
{
//	cout<<a<<endl; //错误代码,a是非静态数据成员
	cout<<"Sum="<<Sum<<endl;
}

void main()
{
	Myclass M(1,2,3);
	M.GetSum();
	Myclass N(4,5,6);
	N.GetSum();
	Myclass::GetSum();
}

关于静态成员函数,可以总结为以下几点:

  • 出现在类体外的函数定义不能指定关键字static;
  • 静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
  • 非静态成员函数可以任意地访问静态成员函数和静态数据成员;
  • 静态成员函数不能访问非静态成员函数和非静态数据成员;
  • 由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;
  • 调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:
    <类名>::<静态成员函数名>(<参数表>)
    调用类的静态成员函数。

posted @ 2010-12-11 09:49 haozi 阅读(137) | 评论 (0)编辑 收藏

好难~~~

    我感觉路途好艰难!!!!

posted @ 2010-10-10 19:16 haozi 阅读(123) | 评论 (0)编辑 收藏

新的开始

  哈 好久没有些题目了! 这学期新的开始,开始再刷刷题目,继续熟悉一下写法!  

posted @ 2010-09-04 21:57 haozi 阅读(89) | 评论 (0)编辑 收藏

数据结构和算法

      我的天啊,我的数据结构和算法真的是学得不咋地! 怎么我感觉我都没有学过似的! 郁闷死了! 计算机这东西真的不是一时半伙可以学会的! 再加上我这笨笨的脑袋瓜子!

posted @ 2010-07-13 16:00 haozi 阅读(106) | 评论 (0)编辑 收藏

突然又想学习c#

  最近半个月都没有写程序! 不知道是不是天气的原因! 哈哈 也许真的是借口!其实不是烦躁! 然后最近想学c#,因为想学做应用程序,和界面! 自己太嫩了!

posted @ 2010-06-30 08:51 haozi 阅读(126) | 评论 (0)编辑 收藏

pku + 2387

       很郁闷,其实是参考别人的代码才弄明白,我也知道很简单,但是写就。。。看来路还很长很长,不知道怎么用堆! 这题还是用普通的结构!这个算法用的是贪心的算法~~书上思想都有的!
 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 using namespace std;
 5 #define MAX 0x7fffffff
 6 
 7 bool flag[2001];
 8 int s1[2001][2001];
 9 int dv[2001];
10 
11 void di( int t1 )
12 {
13     for(int i = 1;i <= t1;i++//起点 例如例子 是从 5 返回 1 所以 5为起点
14         dv[i]=s1[t1][i];
15     flag[t1] = true;
16     int wei;
17     for ( int i = 1; i != t1; ++i )
18     {
19         int min = MAX;
20         for ( int j = 1; j <= t1; ++j )
21         {
22             if ( flag[j] != true && dv[j] < min  )
23             {
24                 wei = j;
25                 min = dv[j];
26             }
27         }
28         if( min == MAX )
29             return ; //说明已经没有路了
30         flag[wei] = true;
31         for ( int k = 1; k <= t1; ++k )
32             if( flag[k] != true && s1[wei][k] < MAX && s1[wei][k] + dv[wei] < dv[k] && s1[wei][k] < MAX )
33                 dv[k] = s1[wei][k] + dv[wei];
34     }
35 }
36 
37 void init( int &t1 )
38 {
39     for ( int i = 1; i != t1+1++i  )
40         for ( int j = 1; j != t1+1++j )
41             if ( i == j )
42                 s1[i][j] = 0;
43             else s1[i][j] = MAX;
44 }
45 
46 int main()
47 {
48     //freopen( "in.txt","r",stdin );
49     int n,t;
50     cin >> t >> n;
51     init( n );
52     for ( int i = 1; i != t + 1++i )
53     {
54         int n1,n2,n3;
55         cin >> n1 >> n2 >> n3;
56         if ( n3 < s1[n1][n2] )
57         {
58             s1[n1][n2] = n3;
59             s1[n2][n1] = n3;
60         }
61     }
62     di( n );
63     cout << dv[1<< endl;
64     return 0;
65 }
66 
67 

posted @ 2010-06-15 15:11 haozi 阅读(168) | 评论 (0)编辑 收藏

郁闷

         突然发现数据结构有没有学好! 瓦 我真的太垃圾了!  图论... 搞了半天理论懂了,怎么实现研究半天! 郁闷... 真希望有个大牛能在身边指导一点! 不然自习真的很累! 都不知道,老师是干什么用的! 郁闷~~~~

posted @ 2010-06-14 16:00 haozi 阅读(78) | 评论 (0)编辑 收藏

3天假期

       3天假期,其实自己已经安排好了,3天,在寝室把图论基础给搞懂了! 昨天发现,其实数据结构和算法书确实都看了,但是实践起来还是有好多不明白,3天准备,先从最薄弱的图论开始! 加油~~~ 3天 希望别浪费太多时间! 当然,世界杯肯定得看的,但是时间自己把握咯!阿哈哈!~~

posted @ 2010-06-13 14:08 haozi 阅读(115) | 评论 (0)编辑 收藏

pku + 1887

    水题一道!
    
 1 #include <iostream>
 2 #include <vector>
 3 #include <new>
 4 using namespace std;
 5 
 6 struct nod {
 7     int num;
 8     int max_num;
 9 };
10 
11 int m = 1;
12 
13 void ji_suan( vector<nod *> &v2 )
14 {
15     int max = 1;
16     for ( vector<nod *> ::iterator p = v2.begin(),q = v2.end(); p != q; ++p )
17     {
18         for ( vector <nod *> ::iterator p1 = p + 1; p1 != q; ++p1 )
19         {
20             if ( (*p)->num > (*p1)->num )
21             {
22                 if ( (*p)->max_num + 1 > (*p1)->max_num )
23                 {
24                     (*p1)->max_num = (*p)->max_num + 1;
25                     if ( max < (*p1)->max_num )
26                         max = (*p1)->max_num;
27                 }
28             }
29         }
30     }
31     printf ( "Test #%d:\n",m++ );
32     cout << "  maximum possible interceptions: " << max << endl;
33 }
34 
35 int main()
36 {
37     //freopen( "in.txt","r",stdin );
38     vector<nod *> v1;
39     int num;
40     while ( cin >> num && num != -1 )
41     {
42         int n;
43         nod *= new nod;
44         p->max_num = 1;
45         p->num = num;
46         v1.push_back(p);
47         while ( cin >> n && n != -1 )
48         {
49             p = new nod;
50             p->num = n;
51             p->max_num = 1;
52             v1.push_back(p);
53         }
54         ji_suan( v1 );
55         v1.clear();
56         cout << endl;
57     }
58     return 0;
59 }

posted @ 2010-06-10 12:14 haozi 阅读(163) | 评论 (0)编辑 收藏

pku + 1989 最短非子序列

假设有排序的个数为n,则其最短的非子序长度,可由下面方法求得。

如果存在其有包括全排序的一个最小组合,(1,2,...n),(次序不限,只要有1...n的数字就行了,也有可能有重复数字)

找到其所有这样组合。可合成()()()...()[],( 设有k个括号,[]里的元素可能为空)
则其最短的非子序长度为k+1;
原因:
长度为k的子序,都可由前k个括号里抽出一个数组成。
但对于k+1,就找不到一个组合,因为最后一个组合里少了需要的最后一个数。

如本例子中:
14 5
1
5
3
2
5
1
3
4
4
2
5
1
2
3

首先有(1,5,3,2,5,1,3,4)(4,2,5,1,2,3)[]
故其最短非子序长度为3;
 1 #include <iostream>
 2 #include <new>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 int main()
 8 {
 9     //freopen( "in.txt","r",stdin );
10     int n,k;
11     cin >> n;
12     cin >> k;
13     vector<bool> v1( k+1,false );
14     int num = 1;
15     for ( int i = 0,j = 0,k1; i != n; ++i )
16     {
17         cin >> k1;
18         if ( v1[k1] == false )
19         {
20             ++j;
21             v1[k1] = true;
22         }
23         if ( j == k )
24         {
25             j = 0;
26             ++num;
27             for ( int k2 = 0; k2 != v1.size(); ++k2 )
28                 v1[k2] = false;
29         }
30     }
31     cout << num << endl;
32     
33 }
34 
35                 
36 
37 
38 

posted @ 2010-06-09 21:39 haozi 阅读(530) | 评论 (0)编辑 收藏

仅列出标题
共4页: 1 2 3 4 
<2010年6月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

导航

统计

常用链接

留言簿

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜