在讲到extern和static的时候先了解一下定义和声明的基本概念
定义(define):
A variable is defined when the compiler allocates the storage for the variable,就是我们的变量个其存储的具体值相关联
声明(declared)
编译器声明这个变量的存在,宣告其类型但是并不关联某个存储的具体值
你可以声明一个变量多次,但是你只能定义其一次并且给一个范围,我们定义一个变量也是声明,但不是所有的声明都是定义
我们在全局声明/定义一个变量最好的一个方法是在头文件中用关键字extern
声明一个变量
在我们工程中,一般用一个头文件声明全部所需的全局变量(当然用extern
),然后在所有其他的.c文件中include这个头文件,假设我们有三个文件分别是file3.h
,file1.c
,file2.c
内容分别如下
var.h
extern int global_var;
var.c
#include "var.h"
#include "prog1.h" //function declarations,我们示例中没有将函数原型头文件写出来
int global_var = 33;
int increment(void) { return global_variable++ }
main.c
#include "var.h"
#include "prog1.h"
#include
//注意我们没有include file1.c
void use_it(void){
printf("global var : %d\n",global_var++);
}
然后我们编译 (记住不编译头文件)
gcc main.c var.c -o out.c
为什么我们的main不include var.c就知道global_var的具体值呢?因为我们说过一个全局变量只能定义一次,但是可以声明多次,global_var分别在main,c和var.c中声明了,但是只在var.c中定义,换个角度,global_var的生命周期是全局也就是整个软件的生命周期,整个软件的生命周期包含三个文件,且global_var不定义在堆栈中,而是声明在bss中,定义在initialed data区域中
static也是全局但是其作用域不是全局而是本文件中,所以其他的文件include一个含有static的头文件,且试图定义他会报错,因为static变量的作用域只在声明他的头文件中
还是上述的程序但是我们把extern改为static了
var.h
static int global_var;
var.c
#include "var.h"
#include "prog1.h" //function declarations,我们示例中没有将函数原型头文件写出来
int global_var = 33;
int increment(void) { return global_variable++ }
main.c
#include "var.h"
#include "prog1.h"
#include
//注意我们没有include file1.c
void use_it(void){
printf("global var : %d\n",global_var++);
}
开始编译发现错误
简而言之就是我们的class里面搞一个static的成员,我们知道static的作用域虽然是全局只存在于本文件,那么将一个static放在一个class中间是什么意思呢?
在Cpp的类中使用static就不再和C一样局限于定义的文件中了,在Cpp的class中用static修饰成员有以下的特点
我们写一个程序,写一个class,在其public中搞一个static member,且在class的构造函数中对这个static member + 1,意味着此static成员作用是统计有多少个class对象成员
static_mamber.h
using namespace std;
class Box{
public:
static int objcount;
Box(double l,double b, double h);
double volume();
private:
double length;
double breadth;
double height;
};
static_member.cpp
#include "static_member.h"
#include
using namespace std;
int Box::objcount = 0; //static成员的初始化在创建所有的class对象之前
//构造函数
Box::Box(double l, double b, double h)
:length(l),breadth(b),height(h){
cout << "construct is called," << endl;
objcount++;
}
double
Box::volume(){
return length * breadth * height;
}
main.cpp
#include "static_member.h"
#include
using namespace std;
int main(void){
Box Box1(3.3,1.2,1.5);
Box Box2(8.5,6.0,2.0);
cout << "total Box object is "<< Box::objcount << endl;
return 0;
}
编译
g++ static_member.cpp main.cpp -o static_member.o
得到结果
construct is called,
construct is called,
total Box object is 2
注意class是全局的也就是extern的因为在所有block(
{}
)外部的变量或者class或者函数如果不加static都默认是extern
为什么我们的static成员要先初始化,因为我们类中的对象除了static是decleared,其余的成员都是definitely,为什么?因为我们的static是全部obj共享,所以其不在固定的栈中而是,data区域中,我们要在全局显示的定义一下他,不然编译器就会报错
注意!!!
我们不能在构造函数的initialize list里面不能初始化static
变量,因为static
只能被初始化一遍,假如我们放在类的构造函数的初始化列表中初始化static
,意味着每次创建class 对象都static
都会被初始化一遍,但是static
是多个对象共享,她只能被初始化一遍,所以错了,但是你放在构造函数的body中是可以的,因为body中是对static
变量reassign而非初始化,所以是可行的,我们的static
对象放在data区域,全局仅此一份,只能初始化一次,示例代码
class A{
public:
static int count;
A(int i): /*count(i)*/{ //错误!不能在initialize list里面初始化static 对象,因为每一次实例化对象都会对initialize list初始化一遍
count = i; //可以!因为构造函数body中对static成员赋值相当于reassign
}
};
在C语言中extern修饰后的变量或者函数,可以在其他的文件中进行使用(需要include定义extern变量或者函数的头文件),但是static则不行,static和extern的作用域都是全局但是,static只允许本文件内对其修饰的变量更改,而extern允许在任何文件中更改
在C++中static修饰的是某个class的一个成员,和C中的static完全不一样,首先C++中如果在头文件中声明某个class的某个成员是static,那么我们在其他文件中可以定义他(前提include对于的头文件),这是在C中是不行的,且C++ static member in clss意思是为此class创建一个独一无二的成员,不论你的class实例化多少次,static成员就一个,其他的class对象都是其copy,并且我们可以随时随地修改这个static成员