在C++中全局初始化类的正确方法

Correct way of initializing a class globally in C++

本文关键字:方法 初始化 C++ 全局      更新时间:2023-10-16

我知道全局是不好的,但作为一种实践,这是初始化多个对象文件之间使用的全局类的正确方法吗?

标题 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;

但是您的testclass需要构造函数的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",并且对其中任何一个变量的更改都不会影响另一个变量。