C++ 类的全局实例(跨多个文件)

C++ 类的全局实例(跨多个文件),c++,codeblocks,C++,Codeblocks,我正在处理C::B中的一个项目,需要跨多个项目文件使用类的全局实例。(我不熟悉头文件和全局类的用法) 我已经声明、定义、初始化了类和函数,因此: //在复合物中 class Julia { public: double R; double I; void algorithm(); }; Julia J; //在complex.cpp中 #include "complex.h" void Julia::algorithm() { //fn body he

我正在处理C::B中的一个项目,需要跨多个项目文件使用类的全局实例。(我不熟悉头文件和全局类的用法)
我已经声明、定义、初始化了类和函数,因此:

//在复合物中

class Julia
{
    public:
    double R;
    double I;
    void algorithm();
};
Julia J;
//在complex.cpp中

#include "complex.h"
void Julia::algorithm()
{ 
    //fn body here
}
//in main.cpp

#include"complex.h"
int main()
{
    //calls initialize() and display()
}

void initialize()
{
    //...some code(irrelevant)
    cin>>J.R>>J.I;
}

void display()
{
    J.algorithm();
    //some more (irrelevant) code
}
在构建和运行代码时,我得到一个错误——“first defined here”,构建日志显示:

obj\Debug\complex.o:complex.cpp:(.bss+0x3bf0):'J'的多个定义 obj\Debug\main.o:C:/Users/ShA/Documents/etf_build/main.cpp:20:首先在此处定义

[这是为了我的12年级项目,我不认为我会被允许使用单身(限制),即使他们似乎是合适的。]

有人能指出代码中可能出现的错误,以及如何找到解决我遇到的错误的方法吗

宣言

Julia J;
在标题中有
J
的定义,通过将标题包含在两个翻译单元中,即
main.cpp
翻译单元和
complex.cpp
翻译单元

链接器不知道它们(本打算)是相同的定义

在链接器看来,这是对同一事物的两个独立且相互冲突的定义


一个纯粹的技术解决方案是将
J
设置为单例,一个简单的方法是通过函数中的
静态
变量,该变量称为“Meyers单例”:

inline
auto J()
    -> Julia&
{
    static Julia the_object;
    return the_object;
}

上面的技术解决方案是不好的,因为与直接全局变量一样,singleton引入了复杂的任意通信线路,例如通过
init
函数

还有一个更不好的技术解决方案,在头文件中将变量声明为
extern
,并在相应的实现文件中定义它。这是额外的错误,因为在更一般的情况下,它会冒使用未初始化变量的风险。这就是所谓的“静态初始化顺序FASCO”,并在C++ FAQ中讨论。 您应该更改设计,让
main
创建
Julia
实例,而不是这些技术解决方案

它可以传递给被调用的函数

如果您发现它被传递给许多函数,特别是作为第一个参数,那么这些函数可能应该是
Julia
类的成员函数,或者您应该为此引入一个新类

在复合物中

class Julia
{
    public:
    double R;
    double I;
    void algorithm();
};
Julia J;
juliaj

这是你的错误。任何包含complex.h的源文件都有自己的
J
。这违反了法律

如果使用全局变量
J
的唯一位置是
int main
,则没有理由将该变量设置为全局变量。使
J
成为主函数中的局部变量。声明只在一个位置使用的全局变量是错误的


另一方面,如果您在多个文件中使用该变量,那么您所做的也是错误的。在这种情况下,
complex.h
头文件应使用
extern
关键字限定变量
J
。现在,您可以在多个位置引用该全局文件(但请注意以下问题)。可以在多个位置引用该变量。只需在一个位置定义该变量。

类Julia
声明(在头文件中)中放置一个
静态Julia&GetInstance()
函数

Julia
Julia J
)的实例放在源文件中。然后在
GetInstance()
实现内部(也在源文件中),返回
J

复合物

class Julia
{
    public:
    double R;
    double I;
    void algorithm();
    static Julia& getInstance();
};
复杂的

#include "complex.h"
Julia J;
void Julia::algorithm()
{ 
    //fn body here
}
Julia& Julia::getInstance() { return J; }

提到静态初始化顺序的失败,却提倡使用一个简单的全局变量,这是不一致的。不管怎么说,这是个不好的建议。@Cheersandhth.-Alf--我特别说过“当心”。如果一个简单的全局变量就足够了,请使用它。如果这导致初始化订单出现问题,请不要。就这么简单。你倾向于把事情复杂化。就我个人而言,我讨厌(也讨厌)成为代码的维护者。也就是说,我也不愿意成为我自己编写的代码的维护者。那种认为避免简单的新手错误就是“过度复杂化”的想法让我感到困惑。我不想维护你的代码。在我的时代,我维护了一些非常丑陋的代码。也就是说,创建潜在的bug吸引器可以是工作安全的一部分。所以,这一切都取决于目的。@Cheers-Sandhth.-Alf——一个人应该总是调用广义相对论和研究生水平的量子力学,即使是为了解决一个简单的块滑下斜坡的问题,这个想法让我感到困惑。所以,除了
extern
关键字缺失之外,其余的代码语法看起来还可以吗?因为,在complex.h中声明它为
extern
之后,
main
中有一个错误,上面写着“未定义对J的引用”,所以根据您的建议,
main
创建实例,传递它,等等,但是类仍然是全局的[而不是实例]?@Sh.a是的。但这是上下文建议。当你越来越熟悉这种构造方式时,你会开始编写越来越大的系统,然后你会发现这个“主”控制器功能是一种模式,在整个系统中以小规模重复,但系统本身是以更平等的方式构造的。Bertrand Meyer这样说:“真正的系统没有顶层”。但他在那本书中谈到了更大的系统,我的学生拒绝使用这本书,可能是因为他直到400页左右才显示“主系统…”但请确保初始化所有变量。您甚至可以创建一个
静态juliaj类头文件中的实例,并在源文件中对其进行初始化。