- 浏览: 141726 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (172)
- java (172)
- c# winform 关于窗体最大化时的是否全屏效果与是否遮盖任务栏 (1)
- c# winform 只运行一个程序实例 (1)
- Shiro权限框架 (1)
- Java字节码(.class文件)的代码解析 (1)
- Hibernate、Spring和Struts工作原理及使用理由 (1)
- 基本PKG处理命令 (1)
- 最近写的代码的小结 (1)
- Dual Palindromes (1)
- 编译TortoiseSVN1.7源代码笔记 (1)
- Android项目代码混淆 (1)
- 关于就业叨咕几句 (1)
- Java重定向System.out和System.err (1)
- IHS与WAS集成插件静默安装 (1)
- 专题地图概述 (1)
- 关于MapXtreme2004附带Sample不能运行的问题 (1)
- SQL注入漏洞 (1)
- 回顾过去 展望未来(写给自己) (1)
- DB2认证考试经验谈(700&&701) (1)
- 今天用到了RM格式文件的分割工具RealProducer (1)
- 搜索引擎还是很有发展前途的 (1)
- 泰利德破解,实现学校机房免费上网 (1)
- Arduino 引言:移动互联外设传感展望 (1)
- c/c++ static 用法总结(三版本合一) (1)
- JQuery与xml的组合谈 (1)
- Android开发之消息处理机制(一)——Handler (1)
- Android开发之PopupWindow (1)
- 解析BitmapData.getPixel32()返回值因何不准确 (1)
- 关于Ext引用js的顺序问题 (1)
- Js事件大全 (1)
- 使用JavaFX2.0编写国际象棋游戏 (1)
- Hibernate/JPA常见异常分析与解决 (1)
最新评论
-
amcucn:
这排版看得
Shiro权限框架 -
WAMING5:
这也太紧凑了,眼看花了
Shiro权限框架 -
longzhun:
大虾 ,看得出你很懒啊!发个贴 这样子怎么看!!!
Shiro权限框架 -
swanky_yao:
活干的不细!!
Spring+Hibernate框架下Mysql读写分离、主从数据库配 -
饶首建:
不错,不过用处比较少吧
批处理设ip和dns
<span style=""></span>
最近经历了一些笔试和面试,经常会被问到static关键字的作用,感觉虽然知道一些,但
每次回答的都不够满意,今天在网上查了一下,总结总结,恩,以备后用!
<br>
[size=24px;]综述<br>[/size]static关键字是C, C++中都存在的关键字。static从字面理解,是“静态的“的 意思,与
此相对应的,应该是“动态的“。
static的作用主要有以下3个:
1、扩展生存期;
2、限制作用域;
3、唯一性;
<br>
1、扩展生存期
这一点主要是针对普通局部变量和static局部变量来说的。声明为static的局部变量的生
存期不再是当前作用域,而是整个程序的生存期。
在程序中,常用内存类型主要有堆、栈和静态存储区。要理解static局部变量就必须首先
理解这三种内存类型。
<br>
在C/C++中, 局部变量按照存储形式可分为三种auto, static, register
(谭浩强, 第174-175页)
局部变量的默认类型都是auto,从栈中分配内存。
auto的含义是由程序自动控制变量的生存周期,通常指的就是变量在进入其作用域的时候
被分配,离开其作用域的时候被释放。
而static变量,不管是局部还是全局,都存放在静态存储区。
表面意思就是不auto,变量在程序初始化时被分配,直到程序退出前才被释放;也就是
static是按照程序的生命周期来分配释放变量的,而不是变量自己的生命周期. 如果在
main前设置断点,然后查看static变量,已经被初始化,也就是说static在执行main函数
前已经被初始化。也就是在程序初始化时被分配。
<br>
------------------------------------------------------------------------------
--------------------------------------------
堆:由程序员自己分配释放(用malloc和free,或new和delete) ,如果我们不手动释放,
那就要到程序结束才释放。如果对分配的空间在不用的时候不释放而一味的分配,那么可
能会引起内存泄漏,其容量取决于虚拟内存,较大。
栈:由编译器自动分配释放,其中存放在主调函数中被调函数的下一句代码、函数参数和
局部变量,容量有限,较小。
静态存储区:由在编译时由编译器分配,由系统释放,其中存放的是全局变量、static变
量和常量.
区别:
1) 堆是由低地址向高地址扩展,栈是由高地址向低地址扩展。
2) 堆是不连续的空间,栈是连续的空间。
3) 在申请空间后,栈的分配要比堆的快。对于堆,先遍历存放空闲存储地址的链表、
修改链表、再进行分配;对于栈,只要剩下的可用空间足够,就可分配到,如果不够,那
么就会报告栈溢出。
4) 栈的生命期最短,到函数调用结束时;静态存储区的生命期最长,到程序结束时;
堆中的生命期是到被我们手动释放时(如果整个过程中都不手动释放,那就到程序结束时
)。
------------------------------------------------------------------------------
--------------------------------------------
<br>
2、限制作用域
这一点相对于普通全局变量和static全局变量来说的。
对于全局变量而言,不论是普通全局 变量还是static全局变量,其存储区都是静态存储区
,因此在内存分配上没有什么区别。
区 别在于:
1) 普通的全局变量和函数,其作用域为整个程序或项目,外部文件(其它cpp文件)可以
通过extern关键字访问该变量和函数。一般不提倡这种用法,如果要在多个cpp文件间共享
数据,应该将数据声明为extern类型。
在头文件里声明为extern:
extern int g_value; // 注意,不要初始化值!
然后在其中任何一个包含该头文件的cpp中初始化(一次)就好:
int g_value = 0; // 初始化一样不要extern修饰,因为extern也是声明性关键字;
然后所有包含该头文件的cpp文件都可以用g_value这个名字访问相同的一个变量;
<br>
2) static全局变量和函数,其作用域为当前cpp文件,其它的cpp文件不能访问该变量和
函数。如果有两个cpp文件声明了同名的全局静态变量,那么他们实际上是独立的两个变量
。
<br>
static函数的好处是不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其
它文件中的函数同名。
<br>
头文件中的static变量
如果在一个头文件中声明:
static int g_vaule = 0;
那么会为每个包含该头文件的cpp都创建一个全局变量,但他们都是独立的;所以也
不建议这样的写法,一样不明确需要怎样使用这个变量,因为只是创建了一组同名而不同
作用域的变量。
<br>
3、数据唯一性
这是C++对static关键字的重用。主要指静态数据成员/成员函数。
表示属于一个类而不是属于此类的任何特定对象的变量和函数. 这是与普通成员函数的最
大区别, 也是其应用所在, 比如在对某一个类的对象进行计数时, 计数生成多少个类的实
例, 就可以用到静态数据成员. 在这里面, static既不是限定作用域的, 也不是扩展生存
期的作用, 而是指示变量/函数在此类中的唯一性. 这也是”属于一个类而不是属于此类的
任何特定对象的变量和函数”的含义. 因为它是对整个类来说是唯一的, 因此不可能属于
某一个实例对象的. (针对静态数据成员而言, 成员函数不管是否是static, 在内存中只有
一个副本, 普通成员函数调用时, 需要传入this指针, static成员函数调用时, 没有this
指针. )
static数据成员的初始化:
(1) 初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆。
(2) 初始化时不加该成员的访问权限控制符private,public等。
(3) 初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不
是对象的成员。
(4) 静态数据成员是静态存储的,它是静态生存期,必须对它进行初始化。
<br>
Static成员函数
静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因
此,对静态成员的引用不需要用对象名。
静态成员函数仅能访问静态的数据成员,不能访问非静态的数据成员,也不能访问非静态
的成员函数,这是由于静态的成员函数没有this指针。
<br>
<span style="color: rgb(51,51,51); font-family: Tahoma,Verdana,STHeiTi,simsun,sans-serif; font-size: 14px; line-height: 21px;"></span>
[size=24px;]在C语言中[/size],static的字面意思很容易把我们导入歧途,其实它的作用有三条。
(1)先来介绍它的第一条也是最重要的一条:隐藏。
当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。为理解这句话,我举例来说明。我们要同时编译两个源文件,一个是a.c,另一个是main.c。
下面是a.c的内容
char a = 'A'; // global variable
void msg()
{
printf("Hello\n");
}
下面是main.c的内容
int main(void)
{
extern char a;// extern variable must be declared before use
printf("%c ", a);
(void)msg();
return 0;
}
程序的运行结果是:
A Hello
你可能会问:为什么在a.c中定义的全局变量a和函数msg能在main.c中使用?前面说过,所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。此例中,a是全局变量,msg是函数,并且都没有加static前缀,因此对于另外的源文件main.c是可见的。
如果加了static,就会对其它源文件隐藏。例如在a和msg的定义前加上static,main.c就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。Static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏,而对于变量,static还有下面两个作用。(2)static的第二个作用是保持变量内容的持久。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。虽然这种用法不常见,但我还是举一个例子。
#include <stdio.h>
int fun(void){
static int count = 10;// 事实上此赋值语句从来没有执行过
return count--;
}
int count = 1;
int main(void)
{
printf("global\t\tlocal static\n");
for(; count <= 10; ++count)
printf("%d\t\t%d\n", count, fun());
return 0;
}
程序的运行结果是:
global local static
1 10
2 9
3 8
4 7
5 6
6 5
7 4
8 3
9 2
10 1
(3)static的第三个作用是默认初始化为0。其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加’\0’太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是’\0’。不妨做个小实验验证一下。
#include <stdio.h>
int a;
int main(void)
{
int i;
static char str[10];
printf("integer: %d; string: (begin)%s(end)", a, str);
return 0;
}
程序的运行结果如下
integer: 0; string: (begin)(end)
最后对static的三条作用做一句话总结。首先static的最主要功能是隐藏,其次因为static变量存放在静态存储区,所以它具备持久性和默认值0。
另外:
一、c程序存储空间布局<br><br>
C程序一直由下列部分组成:<br><br>
1)正文段——CPU执行的机器指令部分;一个程序只有一个副本;只读,防止程序由于意外事故而修改自身指令;<br><br>
2)初始化数据段(数据段)——在程序中所有赋了初值的全局变量,存放在这里。<br><br>
3)非初始化数据段(bss段)——在程序中没有初始化的全局变量;内核将此段初始化为0。<br><br>
4)栈——增长方向:自顶向下增长;自动变量以及每次函数调用时所需要保存的信息(返回地址;环境信息)。<br><br>
5)堆——动态存储分。<br><br>
|-----------|<br>
| |<br>
|-----------|<br>
| 栈 |<br>
|-----------|<br>
| | |<br>
| |/ |<br>
| |<br>
| |<br>
| /| |<br>
| | |<br>
|-----------|<br>
| 堆 |<br>
|-----------|<br>
| 未初始化 |<br>
|-----------|<br>
| 初始化 |<br>
|-----------|<br>
| 正文段 |<br>
|-----------|<br><br>
二、 面向过程程序设计中的static<br><br>
1. 全局静态变量<br><br>
在全局变量之前加上关键字static,全局变量就被定义成为一个全局静态变量。<br><br>
1)内存中的位置:静态存储区(静态存储区在整个程序运行期间都存在)<br><br>
2)初始化:未经初始化的全局静态变量会被程序自动初始化为0(自动对象的值是任意的,除非他被显示初始化)<br><br>
3)作用域:全局静态变量在声明他的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。<br><br>
定义全局静态变量的好处:<br><br>
<1>不会被其他文件所访问,修改<br><br>
<2>其他文件中可以使用相同名字的变量,不会发生**。<br><br>
2. 局部静态变量<br><br>
在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量。<br><br>
1)内存中的位置:静态存储区<br><br>
2)初始化:未经初始化的全局静态变量会被程序自动初始化为0(自动对象的值是任意的,除非他被显示初始化)<br><br>
3)作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域随之结束。<br><br>
注:当static用来修饰局部变量的时候,它就改变了局部变量的存储位置,从原来的栈中存放改为静态存储区。但是局部静态变量在离开作用域之后,并没有被销毁,而是仍然驻留在内存当中,直到程序结束,只不过我们不能再对他进行访问。<br><br>
当static用来修饰全局变量的时候,它就改变了全局变量的作用域(在声明他的文件之外是不可见的),但是没有改变它的存放位置,还是在静态存储区中。<br><br>
3. 静态函数<br><br>
在函数的返回类型前加上关键字static,函数就被定义成为静态函数。<br><br>
函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。<br><br>
定义静态函数的好处:<br><br>
<1> 其他文件中可以定义相同名字的函数,不会发生**<br><br>
<2> 静态函数不能被其他文件所用。<br><br>
存储说明符auto,register,extern,static,对应两种存储期:自动存储期和静态存储期。<br><br>
auto和register对应自动存储期。具有自动存储期的变量在进入声明该变量的程序块时被建立,它在该程序块活动时存在,退出该程序块时撤销。<br><br>
关键字extern和static用来说明具有静态存储期的变量和函数。用static声明的局部变量具有静态存储持续期(static storage duration),或静态范围(static extent)。虽然他的值在函数调用之间保持有效,但是其名字的可视性仍限制在其局部域内。静态局部对象在程序执行到该对象的声明处时被首次初始化。<br><br>
扩展分析:<br><br>
术语static有着不寻常的历史.起初,在C中引入关键字static是为了表示退出一个块后仍然存在的局部变量。随后,static C中有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。为了避免引入新的关键字,所以仍使用static关键字来表示这第二种含义。最后,<br><br>
C++重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数(与Java中此关键字的含义相同)。<br><br>
C语言程序可以看成由一系列外部对象构成,这些外部对象可能是变量或函数。而内部变量是指定义在函数内部的函数参数及变量。外部变量定义在函数之外,因此可以在许多函数中使用。由于C语言不允许在一个函数中定义其它函数,因此函数本身只能是“外部的”。<br>
由于C语言代码是以文件为单位来组织的,在一个源程序所有源文件中,一个外部变量或函数只能在某个文件中定义一次,而其它文件可以通过extern声明来访问它(定义外部变量或函数的源文件中也可以包含对该外部变量的extern声明)。<br>
而static则可以限定变量或函数为静态存储。如果用static限定外部变量与函数,则可以将该对象的作用域限定为被编译源文件的剩余部分。通过 static限定外部对象,可以达到隐藏外部对象的目的。因而,static限定的变量或函数不会和同一程序中其它文件中同名的相冲突。如果用 static限定内部变量,则该变量从程序一开始就拥有内存,不会随其所在函数的调用和退出而分配和消失。<br>
C语言中使用静态函数的好处:<br><br>
1. 静态函数会被自动分配在一个一直使用的存储区,直到退出应用程序实例,避免了调用函数时压栈出栈,速度快很多。<br>
2. 关键字“static”,译成中文就是“静态的”,所以内部函数又称静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件。 使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名,因为同名也没有关系。<br><br>
c语言中static的语义<br>
1.static变量:<br>
1).局部<br>
a.静态局部变量在函数内定义,生存期为整个源程序,但作用域与自动变量相同,只能在定义该变量的函数内使用。退出该函数后, 尽管该变量还继续存在,但不能使用它。<br>
b.对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。<br>
2).全局<br>
全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。但是他们的作用域,非静态全局 变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。<br>
2.static函数(也叫内部函数)<br>
只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。区别于一般的非静态函数(外部函数)<br>
static在c里面可以用来修饰变量,也可以用来修饰函数。<br>
先看用来修饰变量的时候。变量在c里面可分为存在全局数据区、栈和堆里。其实我们平时所说的堆栈是栈而不包含对,不要弄混。<br>
int a ;<br>
main()<br>
{<br>
int b ;<br>
int c* = (int *)malloc(sizeof(int));<br>
}<br>
a是全局变量,b是栈变量,c是堆变量。<br>
static对全局变量的修饰,可以认为是限制了只能是本文件引用此变量。有的程序是由好多.c文件构成。彼此可以互相引用变量,但加入static修饰之后,只能被本文件中函数引用此变量。<br>
static对栈变量的修饰,可以认为栈变量的生命周期延长到程序执行结束时。一般来说,栈变量的生命周期由OS管理,在退栈的过程中,栈变量的生命也就结束了。但加入static修饰之后,变量已经不在存储在栈中,而是和全局变量一起存储。同时,离开定义它的函数后不能使用,但如再次调用定义它的函数时,它又可继续使用, 而且保存了前次被调用后留下的值。<br>
static对函数的修饰与对全局变量的修饰相似,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。<br>
static 声明的变量在C语言中有两方面的特征:<br>
1)、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。<br>
2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别
[size=24px;]<br>[/size]
[size=24px;]在c++中,[/size]
<span style="font-family: simsun; font-size: 14px; line-height: 23px;">(1)局部静态变量<br>
(2)外部静态变量/函数<br>
(3)静态数据成员/成员函数<br>
下面就这三种使用方式及注意事项分别说明<br><br>
一、局部静态变量<br>
在C/C++中, 局部变量按照存储形式可分为三种auto, static, register<br>
( <C语言程序设计(第二版)> 谭浩强, 第174-175页)<br>
与auto类型(普通)局部变量相比, static局部变量有三点不同<br>
1. 存储空间分配不同<br>
auto类型分配在栈上, 属于动态存储类别, 占动态存储区空间, 函数调用结束后自动释放, 而static分配在静态存储区, 在程序整个运行期间都不释放. 两者之间的作用域相同, 但生存期不同.<br>
2. static局部变量在所处模块在初次运行时进行初始化工作, 且只操作一次<br>
3. 对于局部静态变量, 如果不赋初值, 编译期会自动赋初值0或空字符, 而auto类型的初值是不确定的. (对于C++中的class对象例外, class的对象实例如果不初始化, 则会自动调用默认构造函数, 不管是否是static类型)<br><br>
特点: static局部变量的”记忆性”与生存期的”全局性”<br>
所谓”记忆性”是指在两次函数调用时, 在第二次调用进入时, 能保持第一次调用退出时的值. <br>
示例程序一<br>
#include <iostream><br><br>
using namespace std;<br><br>
void staticLocalVar()<br>
{<br>
static int a = 0; // 运行期时初始化一次, 下次再调用时, 不进行初始化工作<br>
cout < < "a= " < <a < <endl;<br>
++a;<br>
}<br><br>
int main()<br>
{<br>
staticLocalVar(); // 第一次调用, 输出a=0<br>
staticLocalVar(); // 第二次调用, 记忆了第一次退出时的值, 输出a=1<br>
return 0;<br>
}<br><br>
应用:<br>
利用”记忆性”, 记录函数调用的次数(示例程序一)<br>
利用生存期的”全局性”, 改善”return a pointer / reference to a local object”的问题. Local object的问题在于退出函数, 生存期即结束,. 利用static的作用, 延长变量的生存期.<br>
示例程序二:<br>
// IP address to string format<br>
// Used in Ethernet Frame and IP Header analysis<br>
const char * IpToStr(UINT32 IpAddr)<br>
{<br>
static char strBuff[16]; // static局部变量, 用于返回地址有效<br>
const unsigned char *pChIP = (const unsigned char *)&IpAddr;<br>
sprintf(strBuff, "%u.%u.%u.%u ", pChIP[0], pChIP[1], pChIP[2], pChIP[3]);<br>
return strBuff;<br>
}<br><br>
注意事项:<br>
1. “记忆性”, 程序运行很重要的一点就是可重复性, 而static变量的”记忆性”破坏了这种可重复性, 造成不同时刻至运行的结果可能不同.<br>
2. “生存期”全局性和唯一性. 普通的local变量的存储空间分配在stack上, 因此每次调用函数时, 分配的空间都可能不一样, 而static具有全局唯一性的特点, 每次调用时, 都指向同一块内存, 这就造成一个很重要的问题 ---- 不可重入性!!!<br>
这样在多线程程序设计或递归程序设计中, 要特别注意这个问题.<br>
(不可重入性的例子可以参见 <effective C++ (2nd)> (影印版)第103-105页)<br>
下面针对示例程序二, 分析在多线程情况下的不安全性.(为方便描述, 标上行号)<br>
① const char * IpToStr(UINT32 IpAddr)<br>
② {<br>
③ static char strBuff[16]; // static局部变量, 用于返回地址有效<br>
④ const unsigned char *pChIP = (const unsigned char *)&IpAddr;<br>
⑤ sprintf(strBuff, "%u.%u.%u.%u ", pChIP[0], pChIP[1], pChIP[2], pChIP[3]);<br>
⑥ return strBuff;<br>
⑦ }<br>
假设现在有两个线程A,B运行期间都需要调用IpToStr()函数, 将32位的IP地址转换成点分10进制的字符串形式. 现A先获得执行机会, 执行IpToStr(), 传入的参数是0x0B090A0A, 顺序执行完应该返回的指针存储区内容是:”10.10.9.11”, 现执行到⑥时, 失去执行权, 调度到B线程执行, B线程传入的参数是0xA8A8A8C0, 执行至⑦, 静态存储区的内容是192.168.168.168. 当再调度到A执行时, 从⑥继续执行,
由于strBuff的全局唯一性, 内容已经被B线程冲掉, 此时返回的将是192.168.168.168字符串, 不再是10.10.9.11字符串.<br><br>
二、外部静态变量/函数<br>
在C中static有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。, 但为了限制全局变量/函数的作用域, 函数或变量前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。注意此时, 对于外部(全局)变量, 不论是否有static限制, 它的存储区域都是在静态存储区, 生存期都是全局的. 此时的static只是起作用域限制作用, 限定作用域在本模块(文件)内部.<br>
使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。<br>
示例程序三:<br><br>
//file1.cpp<br><br>
static int varA;<br>
int varB;<br>
extern void funA()<br>
{<br>
……<br>
}<br><br>
static void funB()<br>
{<br>
……<br>
}<br><br>
//file2.cpp<br><br>
extern int varB; // 使用file1.cpp中定义的全局变量<br>
extern int varA; // 错误! varA是static类型, 无法在其他文件中使用<br>
extern vod funA(); // 使用file1.cpp中定义的函数<br>
extern void funB(); // 错误! 无法使用file1.cpp文件中static函数<br><br><br><br>
三、静态数据成员/成员函数(C++特有)<br>
C++重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数. 这是与普通成员函数的最大区别, 也是其应用所在, 比如在对某一个类的对象进行计数时, 计数生成多少个类的实例, 就可以用到静态数据成员. 在这里面, static既不是限定作用域的, 也不是扩展生存期的作用, 而是指示变量/函数在此类中的唯一性. 这也是”属于一个类而不是属于此类的任何特定对象的变量和函数”的含义. 因为它是对整个类来说是唯一的, 因此不可能属于某一个实例对象的.
(针对静态数据成员而言, 成员函数不管是否是static, 在内存中只有一个副本, 普通成员函数调用时, 需要传入this指针, static成员函数调用时, 没有this指针. )<br>
请看示例程序四( <effective c++ (2nd)> (影印版)第59页)<br>
class EnemyTarget {<br>
public:<br>
EnemyTarget() { ++numTargets; }<br>
EnemyTarget(const EnemyTarget&) { ++numTargets; }<br>
~EnemyTarget() { --numTargets; }<br>
static size_t numberOfTargets() { return numTargets; }<br>
bool destroy(); // returns success of attempt to destroy EnemyTarget object<br>
private:<br>
static size_t numTargets; // object counter<br>
};<br>
// class statics must be defined outside the class;<br>
// initialization is to 0 by default<br>
size_t EnemyTarget::numTargets;<br><br>
在这个例子中, 静态数据成员numTargets就是用来计数产生的对象个数的.<br>
另外, 在设计类的多线程操作时, 由于POSIX库下的线程函数pthread_create()要求是全局的, 普通成员函数无法直接做为线程函数, 可以考虑用Static成员函数做线程函数.</span><br>
<span style="font-family: simsun; font-size: 14px; line-height: 23px;"><br></span>
<span style="font-family: simsun; font-size: 14px; line-height: 23px;"><span style="font-family: simsun; font-size: 14px; line-height: 23px;">1.static既不是限定作用域的,也不是扩展生存期的作用, 而是指示变量/函数在此类中的唯一性。<br>
楼主的这段话不妥,static是用来限定作用域的,限定在类的作用域。<br>
Static变量的采用,与全局变量有关。<br>
如果用全局变量来在类的所有对象中进行通信的话,好是好,但是破坏了类的封装性。有点象在C中,static把全局变量的作用域限定在本文件(编译单元)中,类的static把“全局变量”的作用域限定在类中。</span><br></span>
<span style="font-family: simsun; font-size: 14px; line-height: 23px;"><span style="font-family: simsun; font-size: 14px; line-height: 23px;"><span style="font-family: simsun; font-size: 14px; line-height: 23px;">2.关于静态成员函数,也是把一个普通函数的作用域限定在类中。正如一个普通函数是外连接的,用static修饰后,把它限定在本文件中。<br>
而把一个成员函数声明成static,则变成了只属于该类的函数。(把它称之为成员函数,是因为其调用时需加类名和作用域运算符::),它没有传递this指针。<br>
Thinking in c++一书中说,静态成员函数没有this指针,所以它不能访问非静态数据成员,也不能调用非静态成员函数。其实,它还是可以访问静态数据成员的,只不过其语法与原来的不同,我写了段代码,在dev-c++中通过了。</span><br></span></span>
<span style="font-family: simsun; font-size: 14px; line-height: 23px;"><span style="font-family: simsun; font-size: 14px; line-height: 23px;"><span style="font-family: simsun; font-size: 14px; line-height: 23px;"><span style="font-family: simsun; font-size: 14px; line-height: 23px;">#include
<iostream><br>
using namespace std;<br>
class A<br>
{<br>
int j;<br>
public:<br>
A(int ii):j(ii){}<br>
A():j(0){}<br>
void print()<br>
{<br>
cout < < "j= " < <j < <endl;<br>
}<br>
static A Add(A& a,A& b)/*是不是有点象友元函数?*/<br>
{<br>
A c;<br>
c.j=a.j+b.j;<br>
cout < < "Add...\n ";<br>
cout < < "In static Add()\n ";<br>
c.print();<br>
return c;<br>
}<br><br>
};<br><br>
int main()<br>
{ <br>
A c(5);<br>
A d(6);<br>
A e(0);<br>
c.print();<br>
d.print();<br>
e=A::Add(c,d);<br>
cout < < "In main()\n ";<br>
e.print();<br>
system( "pause ");<br>
return 0;<br>
}<br>
从这里看,静态成员函数确实没有this指针,但它还是可以访问非静态数据成员,也可以调用非静态成员函数的。<br>
所以,静态成员函数就是作用域仅限于该类的“普通函数”,象友元,没有this指针,但它又只属于该类,调用它时语法怪异,必须加类名和作用域运算符。<br>
如果不是这一点,大多友元函数也没有其他用处,象那些以友元方式重载的运算符,如果把它改成静态成员函数,可能更好一些。</span><br></span></span></span>
<span style="font-family: simsun; font-size: 14px; line-height: 23px;"><span style="font-family: simsun; font-size: 14px; line-height: 23px;"><span style="font-family: simsun; font-size: 14px; line-height: 23px;"><span style="font-family: simsun; font-size: 14px; line-height: 23px;"><br></span></span></span></span>
<span style="font-family: simsun; line-height: 23px;"><span style="font-family: simsun; line-height: 23px;"><span style="font-family: simsun; line-height: 23px;"><span style="font-family: simsun; line-height: 23px;">[size=18px;]注意,以<span style="font-family: simsun; font-size: 14px; line-height: 23px;">上的对静态函数不能调用非静态成员存在认识上的误解,从所举的例子中,并不能证明静态函数可以调用非静态成员,不过,却告诉大家静态函数的一般用法。<br>
所谓静态函数不能调用非静态成员,是指静态函数不参与对象成员的直接调用,比如:<br>
class T{<br>
C c;<br>
static T t;<br>
static T F(T a){<br>
a.c += t.c; // 可以,因为没有直接参与类的成员变量<br>
return a;}<br>
// static C get(){return c;} //不允许 但是 return t.c;却是可以<br>
};[/size]</span></span></span></span></span>
<span style="font-family: simsun; line-height: 23px;"><span style="font-family: simsun; line-height: 23px;"><span style="font-family: simsun; line-height: 23px;"><span style="font-family: simsun; line-height: 23px;">[size=18px;]<span style="font-family: simsun; font-size: 14px; line-height: 23px;"><span style="font-family: simsun; font-size: 14px; line-height: 23px;">另外,静态成员函数的调用同普通成员函数调用一样,可以直接使用.或->
操作符,而不一定必须使用::域操作符。[/size]</span></span></span></span></span></span>
<br>
发表评论
-
Hibernate/JPA常见异常分析与解决
2012-02-07 17:24 15001. ClassNotFoundException: ... -
使用JavaFX2.0编写国际象棋游戏
2012-02-07 16:24 1088前面发布了不少Javafx2的教程,不觉手痒,想尝试一 ... -
Js事件大全
2012-02-04 15:34 784一般事件 事件 ... -
关于Ext引用js的顺序问题
2012-02-02 15:49 759今天自己搞了个ext的helloworld,所需的包都 ... -
解析BitmapData.getPixel32()返回值因何不准确
2012-02-02 12:29 993<div style="widt ... -
Android开发之PopupWindow
2012-01-31 13:48 1675<h1>Android开发之PopupWi ... -
Android开发之消息处理机制(一)——Handler
2012-01-11 15:19 1166<h1>Android开发之消息处理机制( ... -
JQuery与xml的组合谈
2011-12-21 17:18 794JQuery与xml的组合谈 今天谈的是XML,学ja ... -
Arduino 引言:移动互联外设传感展望
2011-12-20 14:08 1325作者:mznewfacer (Wolf Geek) ... -
泰利德破解,实现学校机房免费上网
2011-12-20 13:58 944泰利德破解,实现学校机房免费上网<br> ... -
搜索引擎还是很有发展前途的
2011-12-19 11:49 959相信大家已经听说,在头几天,搜狐推出了一个专业搜索门户 ... -
今天用到了RM格式文件的分割工具RealProducer
2011-12-19 09:19 704项目要加一些视频文件,这些视频都是几个老师对数据结构课 ... -
DB2认证考试经验谈(700&&701)
2011-12-16 17:17 1113很多人都通过了D ... -
回顾过去 展望未来(写给自己)
2011-12-15 16:19 1494本来想用“昨天今天明天”做标题来着,但是人家本山大叔说 ... -
SQL注入漏洞
2011-12-15 12:19 715CSDN上的ASP.NET电子杂志下载下来看,就看到了 ... -
关于MapXtreme2004附带Sample不能运行的问题
2011-12-15 10:54 679</span> -
专题地图概述
2011-12-14 12:49 845<p class="MsoNorma ... -
IHS与WAS集成插件静默安装
2011-12-14 12:04 964<span style="col ... -
Java重定向System.out和System.err
2011-12-13 14:49 1171<div>继承PrintStream类: ... -
关于就业叨咕几句
2011-12-13 11:04 642公司开始去各个学校开宣讲会了,这让我想起又到招聘的季节 ...
相关推荐
C/C++是两种广泛使用的编程语言,特别是在系统级编程、游戏开发和高性能计算等领域。C++是C语言的扩展,引入了面向对象编程的概念。在编程过程中,理解并有效地使用库函数是至关重要的,因为它们提供了标准功能,...
static 关键字是 C 和 C++ 中都存在的关键字,它主要有三种使用方式,其中前两种只在 C 语言中使用,第三种在 C++ 中使用(C 和 C++ 中具体微妙操作不尽相同,本文以 C++ 为准)。 局部静态变量 在 C/C++ 中,局部...
支持最新操作系统WINDOWS 7,它是从事一线教学的大学教师根据C/C++ 初学者的特点,量身定制的一个简单易用的 C/C++程序设计学习与实验软件(支持TC2/TC3、VC6三种编译器,没有使用日期限制,重新集成在VISTA、WINDOWS ...
这个文档压缩包包含普通C/C++中文文档和蓝桥杯比赛时用的文档,C/C++中文文档是最新版,支持到C++20和C18,且包含以前版本的内容。蓝桥杯蓝桥杯C/C++组用的文档比正常文档更简略,但包含了ASCII码表。
C语言/C++基础之冰墩墩源码,适合初学C语言/C++的小伙伴学习研究,博客中有对应的讲解和演示,避免走弯路,费时费力。也真心希望能够帮助正在苦学C语言/C++ 程序设计的小伙伴们,你们的成长是我最大的幸福
#二维码(QRcode)生成算法 C语言/C++ 源码 1. 根据输入字符串识别编码模式; 2. 根据输入字符串长度选择合适的QRcode版本; 3. 将编码转换为二进制位流表示为数据码字; 4. 使用多项式生成纠错码; 5. 将数据码和...
C语言/C++基础之爱心源码,适合初学C语言/C++的小伙伴学习研究,博客中有对应的讲解和演示,避免走弯路,费时费力。也真心希望能够帮助正在苦学C语言/C++ 程序设计的小伙伴们,你们的成长是我最大的幸福
6. **C库的C++封装**:C++对C库中的函数进行了封装,如头文件和分别对应C语言的和,使得C++代码能以更现代的方式来使用这些函数。 7. **C++11及后续版本的新特性**:从C++11开始,C++引入了一系列新特性,如lambda...
C语言/C++基础之爱心程序源码,适合初学C语言/C++的小伙伴学习研究,博客中有对应的讲解和演示,避免走弯路,费时费力。也真心希望能够帮助正在苦学C语言/C++ 程序设计的小伙伴们,你们的成长是我最大的幸福
c语言/c++/qt图形界面
C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域。这份"c/c++帮助文档中文"提供了丰富的中文资源,帮助开发者深入理解和掌握这两种语言。 C语言是最早由Dennis Ritchie在贝尔实验...
《C/C++详细函数大全》是一部综合性的编程资源,涵盖了C和C++语言中的各种函数,旨在为学习者提供详尽的函数介绍、说明及代码示例。此资源源自某培训学校的教学材料,以CHM(Compiled HTML Help)格式呈现,这种格式...
基于C语言/C++版本的元旦倒计时代码,适合初学C语言/C++的小伙伴学习研究,博客中有对应的讲解和演示,避免走弯路,费时费力。也真心希望能够帮助正在苦学C语言/C++ 程序设计的小伙伴们,你们的成长是我最大的幸福
* 头档的作用:头文件和定义文件是C/C++编程中的重要组成部分,需要了解它们的作用和使用方法,以确保代码的正确性和可维护性。 2. 程序的版式: * 空行:在编写C/C++程序时,需要使用空行来分隔不同的代码块,以...
C语言/C++基础之跨年烟花代码,适合初学C语言/C++的小伙伴学习研究,博客中有对应的讲解和演示,避免走弯路,费时费力。也真心希望能够帮助正在苦学C语言/C++ 程序设计的小伙伴们,你们的成长是我最大的幸福
软件集成了高校 C/C++语言教学中使用最多的三种编译器 Visual C++ 6.0 、Turbo C++3.0和Turbo C 2.0 ,给高校 C/C++的实验教学提供了简单易用的软件实验环境(软件没有使用日期限制,可以无限期使用)。与软件配套的...
Dev-C++是一款经典的开源、免费的C语言和C++集成开发环境(IDE),它为程序员提供了编写、编译、调试代码的一体化平台。这款工具因其简洁易用的界面和强大的功能,在初学者和专业开发者中都享有较高的声誉。 1. **...
c / c++ / cpp / stl 中文帮助文档手册chm格式下载 C/C++ 语言参考 基本C/C++ 预处理命令 操作符优先级 转义字符 ASCII码表 基本数据类型 关键字 标准 C 库: Standard C I/O Standard C String...
C语言/C++基础之跨年烟花代码,适合初学C语言/C++的小伙伴学习研究,博客中有对应的讲解和演示,避免走弯路,费时费力。也真心希望能够帮助正在苦学C语言/C++ 程序设计的小伙伴们,你们的成长是我最大的幸福