我知道全局是不好的,但作为一种实践,这是初始化多个对象文件之间使用的全局类的正确方法吗?
标题 1.h
class test {
int id;
public:
test(int in){
id = in;
}
int getId(){
return id;
}
};
extern test t;
文件 1.cc:
#include <iostream>
#include "1.h"
int main(){
std::cout << t.getId() << std::endl;
return 0;
}
文件 2.cc:
#include "1.h"
test t(5);
现在,如果我不是extern
而是在标题中全局static test t(0);
使用static
方法怎么办?
如果我错了,请纠正我,但这可以很好地编译,但是我会在目标文件和最终二进制文件中都有同一t
的 2 个不同的不相关副本?这样不好吗?还是链接器对其进行排序以消除多个副本?
有全局实例,而不是全局类。
您拥有的是一个全局实例。是的,这听起来很正确,直到您到达多个相互依赖的全局实例。然后真正的乐趣将开始。
在全局级别将变量定义为"静态"意味着该变量将仅在编译单元(即".o"文件(中定义,并且编译器不会导出该符号。
换句话说:是的,将有多个具有相同名称的变量,但仅对同一编译单元上的函数可见。
此外,"看不见"并不意味着"无法接近"。您仍然可以提供对变量的访问。例如:
1.小时
struct Test { int value; }; // Class definition
Test& get_t(); // Function declaration
1.cc
#include "1.h"
static Test t; // Variable declared as 'static'
Test& get_t() { return t; };
2.cc
#include "1.h"
#include <iostream>
int main()
{
std::cout << get_t().value << std::endl; // Static variable accessed
}
我使用全局静态方法
static test t;
?
但是您的test
class
需要构造函数的int in
参数,因此您需要:
static test t(0); // or whatever int you want
如果在标头中将extern
转换为static
,则需要在导入标头的每个编译单元中定义一个static
变量。 因此,不同 cpp 文件中的类将不再通过 t "通信",因为每个类都有自己的类。 这很容易出错。
此外,在header
中添加static
的定义是一种极其糟糕的做法。当有人包含标头时,人们不会期望它会创建变量。
将t
声明为extern
是可以接受的做法。 但请注意,如果标头具有通用用途,这可能会降低其其他项目的可重用性。
您感兴趣的更多信息:
- 必读:C++ 关于源文件的核心指南
- 必读:编写标头的准则
- 堆栈溢出:何时建议使用全局变量
- 为什么如果可能的话应该避免全局变量,什么时候可以
如果将变量声明放在任何函数之外,则将变量声明为"全局"。前任:
1.cc
int this_is_global;
从这里开始,您可以在"1.cc"的任何函数中使用该变量。
要在任何其他文件中使用相同的变量,编译器需要了解它:
2.cc
extern int this_is_global;
在这里,关键字extern
告诉编译器变量在其他地方声明,让查找它的任务交给链接器。
如果错过在此处添加extern
关键字,编译器会将其视为新变量,链接器将有两个同名的变量,并会发出错误。除第一个文件外,项目的所有源文件都需要extern
关键字以避免重复符号。
所以常见的做法是在包含文件中添加"extern"声明:
1.cc
int this_is_global;
1.小时
extern int this_is_global;
2.cc
#include "1.h"
另一方面,static
关键字告诉编译器不要导出符号。换句话说:变量将只存在于它声明的源文件中。您可以为每个源文件声明一次,并且将有不同的变量具有相同的名称。前任:
1.小时
static int my_var;
1.cc
#include "1.h"
2.cc
#include "1.h"
这样,您将结束两个变量"my_var",并且对其中任何一个变量的更改都不会影响另一个变量。