C/C++ 变量声明和定义的区别 静态变量的作用

来源:互联网 发布:r230清零软件图解 编辑:程序博客网 时间:2024/06/05 02:50

变量声明和定义的区别

:在学习C/C++的过程中容易混淆变量的声明和定义,先将他们的区别总结如下:

不需要开辟内存空间的是声明,需要开辟内存空间的是定义;

如int a  //定义;

extern int a;//声明


静态变量的作用:

static关键字是C, C++中都存在的关键字, 它主要有三种使用方式, 其中前两种只指在C语言中使用, 第三种在C++中使用(C,C++中具体细微操作不尽相同, 本文以C++为准).
(1)局部静态变量
(2)外部静态变量/函数
(3)静态数据成员/成员函数

1.静态局部变量 

在C/C++中, 局部变量按照存储形式可分为三种auto, static, register。与auto类型(普通)局部变量相比, static局部变量有三点不同:

存储空间分配不同:auto类型分配在栈上, 属于动态存储类别, 占动态存储区空间, 函数调用结束后自动释放, 而static分配在静态存储区, 在程序整个运行期间都不释放. 两者之间的作用域相同, 但生存期不同.static局部变量在所处模块在初次运行时进行初始化工作, 且只操作一次。对于局部静态变量, 如果不赋初值, 编译期会自动赋初值0或空字符, 而auto类型的初值是不确定的. (对于C++中的class对象例外, class的对象实例如果不初始化, 则会自动调用默认构造函数, 不管是否是static类型)。

#include <iostream>

using namespace std;

void staticLocalVar()
{
 static int a = 0; // 运行期时初始化一次, 下次再调用时, 不进行初始化工作
 cout<<"a="<<a<<endl;
 ++a;
}

int main()
{
 staticLocalVar(); // 第一次调用, 输出a=0
 staticLocalVar(); // 第二次调用, 记忆了第一次退出时的值, 输出a=1
 return 0;
}

默认初始化为0, 只初始化一次,全局生命周期(程序结束释放空间) ,可使用范围为当前函数,局部静态变量可以记录访问所在函数的次数等等。

2.外部静态变量/函数

全局静态变量 默认初始化为0 全局生命周期(程序结束释放空间) 可使用范围为当前文件。

3.静态类成员变量

需要在类实现中初始化 全局生命周期(程序结束释放空间) 不只属于某个对象 可使用范围要看声明时的访问权限。

C++重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数. 这是与普通成员函数的最大区别, 也是其应用所在, 比如在对某一个类的对象进行计数时, 计数生成多少个类的实例, 就可以用到静态数据成员. 在这里面, static既不是限定作用域的, 也不是扩展生存期的作用, 而是指示变量/函数在此类中的唯一性. 这也是”属于一个类而不是属于此类的任何特定对象的变量和函数”的含义. 因为它是对整个类来说是唯一的, 因此不可能属于某一个实例对象的. (针对静态数据成员而言, 成员函数不管是否是static, 在内存中只有一个副本, 普通成员函数调用时, 需要传入this指针, static成员函数调用时, 没有this指针. )

C++类中谈到static,我们可以在类中定义static成员,static成员函数!C++primer里面讲过:static成员它不像普通的数据成员,static数据成员独立于该类的任意对象而存在,每个static数据成员是与类关联的对象,并不与该类的对象相关联!这句话可能比较拗口,其实可以这么理解:每个static数据成员可以看成是类的一个对象,而不与该类定义的对象有任何关系!下面我们就来具体看看类中的static数据成员!

static.h文件
2 #include <iostream>
3 #include <string>
4 using namespace std;
5 class Person
6 {
7 private:
8 string name;
9 static int age; // Person类中定义了一个static数据成员age, // 注意在类中不能对static数据成员进行初始化,要初始化的话必须在类外进行定义!
10 public:
11 Person(const string&nm):name(nm)
12 {}
13 void Print()
14 {
15 cout<<name<<" is "<<age<<endl;
16 }
17 };
18 int Person::age=20; // 注意,static数据成员不是通过类构造函数进行初始化的!
                                                     //  在类外定义int Person::age=20;这里前面就不要再加static了。
static.cpp文件
21
22 #include "stdafx.h"
23 #include "static.h"
24 #include <iostream>
25 using namespace std;
26
27 int _tmain(int argc, _TCHAR* argv[])
28 {
29 Person person("tom");
30 person.Print();
31 cout<<endl;
32 return 0;
33 }
如果类中有多个static数据成员,static数据成员初始化的次序是按照static数据成员在类中的声明次序进行初始化的,初始化了之后,就可以使用static数据成员了,我们可以通过作用域操作符从类直接调用static数据成员,或者通过对象,引用,或指向该类类型对象的指针间接调用(这种情况下static数据成员必须是public的访问权限,如果定义在private访问权限下是不行的)。

说到static数据成员,有一种情况不得不提,那就是特殊的const static成员。如上面所述,类的static成员,像普通数据成员一样,不能在类的定义体中进行初始化。只能在类外进行初始化。const int 型的static成员便可以在类定义体内部进行初始化。记住一定只能是const int型的,换成const string ,double都不行的。看下面这段代码:

static.h头文件
#include
<iostream>
#include
<string>
using namespace std;
class Person
{
private:
string name;
static const int age=20;
static string address;
public:
Person(
const string&nm):name(nm)
{}
static string Address()
{
return address;
}
void Print()
{
cout
<<name<<" is "<<age ;
}
};
string Person::address="Beijing";

static.cpp文件

#include
"stdafx.h"
#include
"static.h"
#include
<iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
Person person(
"tom");
person.Print();
cout
<<" and live in "<<person.Address();
cout
<<endl;
return 0;
}
在C++Primer里面有一段注解:const static数据成员在类的定义体中进行了初始化后,还必须在类的定义体之外进行定义。其实这是可要可不要的。上面的代码就没有这段代码实现,其实加上去也是可以的,没有关系。还有一点,static数据成员的类型可以使该成员所属的类类型,非static数据成员被限定为其自生类对象的指针或引用。例如:类定义位如下的情况:

class Person
{
private:
string name;
static const int age=20;
static string address;
static Person person1;
Person
*person2;
Person person3;
public:
Person(
const string&nm):name(nm)
{}
static string Address()
{
return address;
}
void Print()
{
cout
<<name<<" is "<<age ;
}
};
复制代码

如果没有定义person3,则能够顺利通过编译,但是加上了person3就不能通过编译了!

static成员是类的组成部分并不是任何对象的组成部分,因此,static成员函数没有this指针。我们知道,一般而言,类中的成员函数具有一个附加的隐含实参,即指向该类对象的一个指针。这个隐含实参命名为this。因为static成员函数不是任何对象的组成部分,所以static成员函数就没有this形参了。由于成员函数声明为const说明该成员函数不会修改该成员函数所属的对象,所以static成员函数不能声明为const。为什么呢?因为static成员函数不是任何对象的组成部分。static成员函数可以直接访问所属类的static成员,但是不能直接使用非static成员函数!也不能访问static const 类型的成员!在上面的代码中static  string Address()函数中如果是return name或者是return age都不行




0 0
原创粉丝点击