Static 用法
本博客参照:CPlusPlusThings
加上了一些自己的理解
当与不同类型一起使用时,static关键字具有不同的含义。我们可以使用static关键字:
静态变量: 函数中的变量,类中的变量
静态类的成员: 类对象和类中的函数
现在让我们详细看一下静态的这些用法
静态变量
函数中的静态变量
当变量声明为static时,空间将在程序的生命周期内分配。即使多次调用该函数,静态变量的空间也只分配一次,前一次调用中的变量值通过下一次函数调用传递。这对于在C / C ++或需要存储先前函数状态的任何其他应用程序非常有用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#include <iostream>
#include <string>
using namespace std;
void demo()
{
// static variable
static int count = 0;
cout << count << " ";
// value is updated and
// will be carried to next
// function calls
count++;
}
int main()
{
for (int i = 0; i < 5; i++)
demo();
return 0;
}
|
输出:
可以在上面的程序中看到变量count被声明为static。因此,它的值通过函数调用来传递。每次调用函数时,都不会对变量计数进行初始化。
类中的静态变量
初始化
由于声明为static的变量只被初始化一次,因为它们在单独的静态存储中分配了空间,因此类中的静态变量由对象共享。对于不同的对象,不能有相同静态变量的多个副本。也是因为这个原因,静态变量不能使用构造函数初始化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
// variables inside a class
#include <iostream>
using namespace std;
class Apple
{
public:
static int i;
Apple(){
// Do nothing
};
};
int Apple::i = 0; // 要在类外初始化
int main()
{
Apple obj1;
Apple obj2;
obj1.i = 2;
obj2.i = 3;
// prints value of i
cout << obj1.i << " " << obj2.i;
}
|
输出:
静态对象
就像变量一样,对象也在声明为static时具有范围,直到程序的生命周期。
对象是非静态的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#include <iostream>
using namespace std;
class Apple
{
int i;
public:
Apple()
{
i = 0;
cout << "Inside Constructor\n";
}
~Apple()
{
cout << "Inside Destructor\n";
}
};
int main()
{
int x = 0;
if (x == 0)
{
Apple obj;
}
cout << "End of main\n";
}
|
输出:
1
2
3
|
Inside Constructor
Inside Destructor
End of main
|
在上面的程序中,对象在if块内声明为非静态。因此,变量的范围仅在if块内。因此,当创建对象时,将调用构造函数,并且在if块的控制权越过析构函数的同时调用,因为对象的范围仅在声明它的if块内。
如果我们将对象声明为静态,现在让我们看看输出的变化。
对象是静态的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#include <iostream>
using namespace std;
class Apple
{
int i;
public:
Apple()
{
i = 0;
cout << "Inside Constructor\n";
}
~Apple()
{
cout << "Inside Destructor\n";
}
};
int main()
{
int x = 0;
if (x == 0)
{
static Apple obj;
}
cout << "End of main\n";
}
|
输出:
1
2
3
|
Inside Constructor
End of main
Inside Destructor
|
可以清楚地看到输出的变化。现在,在main结束后调用析构函数。这是因为静态对象的范围是贯穿程序的生命周期。
静态函数
就像类中的静态数据成员或静态变量一样,静态成员函数也不依赖于类的对象。允许使用对象和 .
来调用静态成员函数。但建议使用类名和范围解析运算符调用静态成员。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
#include <iostream>
using namespace std;
class Apple
{
public:
void A()
{
_static = 1;
non_static = 1;
B();
cout << "A" << endl;
}
static void B()
{
_static = 1;
non_static = 1; // error
A(); // error
cout << "B" << endl;
}
private:
int non_static;
static int _static;
};
// main function
int main()
{
Apple a;
a.A();
Apple :: B();
}
|
静态成员函数仅能访问静态数据成员或其他静态成员函数,它们无法访问类的非静态数据成员或成员函数。
限定访问范围
static还有限定访问范围的作用(类似于匿名名字空间)
1
2
3
4
5
6
7
8
|
// source1.cpp
extern void sayHello();
const char *msg = "Hello World!\n";
int main()
{
sayHello();
return 0;
}
|
1
2
3
4
5
6
7
|
// source2.cpp
#include <cstdio>
extern char *msg;
void sayHello()
{
printf("%s", msg);
}
|
编译指令:
1
2
3
|
g++ -c source1.cpp -o source1.o
g++ -c source2.cpp -o source2.o
g++ source1.o source2.o -o hello_program
|
g++对于上面两个代码文件是可以正常编译并且打印Hello World!,但如果给source1.cpp中的msg加上static,则会导致undefined reference to ‘msg’的编译错误:
1
2
3
4
5
6
7
8
|
// source1.cpp
extern void sayHello();
static const char* msg = "Hello World!\n";
int main()
{
sayHello();
return 0;
}
|
static关键字将变量的作用域限制在其定义的编译单元内部。这样,msg变量只能在source1.cpp中使用,对其他文件不可见。