简体   繁体   English

如何在C ++中的命名空间之间共享变量?

[英]How to share variables between namespaces in C++?

I come from a C# background so I kindly ask the answers could compare to C#. 我来自C#背景,因此请您将答案与C#进行比较。

I have a namespace with functions and variables to parse input for my program. 我有一个带有函数和变量的名称空间,用于解析程序的输入。 The namespace is defined in a header and a source file. 名称空间在标头和源文件中定义。 I also have defined a struct which have one property for each input param in my program to facilitate communication across classes. 我还定义了一个结构,该结构对程序中的每个输入参数都具有一个属性,以促进跨类的通信。 Like the minimum working example below: 像下面的最小工作示例:

mytypes.h mytypes.h

#ifndef _MYTYPES_H_
#define _MYTYPES_H_
namespace MyTypes
{
    enum class Par1Opt
    {
        opt1,opt2
    };
    struct InputParam_t
    {
        Par1Opt par1;
        int test;
    };
}
#endif // _MYTYPES_H_

myinput.h myinput.h

#ifndef _MYINPUT_H_
#define _MYINPUT_H_
#include <unordered_map>
#include <string>
#include "mytypes.h"
namespace MyInput
{
    static const std::string par1 = "par1";
    static int testVar;
    static MyTypes::InputParam_t inputParam;
    static std::unordered_map<MyTypes::Par1Opt, std::string> Par1OptToStr;
    void InitVariables(void);
}
#endif // _MYINPUT_H_

myinput.cpp myinput.cpp

#include <unordered_map>
#include <string>
#include "mytypes.h"
#include "myinput.h"
namespace MyInput
{
    void InitVariables(void) // set some default values
    {
        inputParam.par1 = MyTypes::Par1Opt::opt1; // default value
        inputParam.test = 10;
        Par1OptToStr = std::unordered_map<MyTypes::Par1Opt, std::string>({
            { MyTypes::Par1Opt::opt1, "opt1" },
            { MyTypes::Par1Opt::opt2, "opt2" }
        });
        testVar = 20;
    }
}

main.cpp main.cpp

#include <iostream>
#include "myinput.h"
int main(int argCount, char* args[])
{
    MyInput::InitVariables(); // expect to set MyInput:: variables here
    std::cout << MyInput::par1 << " = "
        << MyInput::Par1OptToStr[MyInput::inputParam.par1]
        << std::endl; // par1 = 
    std::cout << "inputParam.test = " << MyInput::inputParam.test
        << std::endl; // inputParam.test = 0
    std::cout << "testVar = " << MyInput::testVar
        << std::endl; // testVar = 0
    std::cin.get(); // pause
    // none of the values set for the MyInput:: variables inside InitVariables() method
    // are available in main
}

The questions are: 问题是:

  1. Why are the values set inside InitVariable() not available in main() ? 为什么值内设置InitVariable()不在可用main() Since the variables are static, I would expect (with mainly C# background) that the values would be available anywhere I use #include "myinput.h" . 由于变量是静态的,因此我希望(主要使用C#背景)这些值将在我使用#include "myinput.h"任何位置可用。 How can I solve it? 我该如何解决?

  2. If I remove static keyword from variable declarations in myinput.h , then I get the Multiply defined symbols error. 如果我从myinput.h变量声明中删除了static关键字,那么我会得到“ Multiply defined symbols错误。 Why? 为什么?

Thanks in advance! 提前致谢!

When you declare a global variable in .h file with static specifier, you create a separate variable in each translation unit in which the .h file is included, so the variables referenced in myinput.cpp are not the same as variables referenced from main.cpp despite they have the same names. 当使用static说明符在.h文件中声明全局变量时,您将在包含.h文件的每个转换单元中创建一个单独的变量,因此myinput.cpp中引用的变量与从main.cpp引用的变量不同main.cpp尽管它们具有相同的名称。

When you create it with no specifier, you violate One Definition Rule . 在没有指定符的情况下创建它时,会违反“ 一个定义规则”

What you should do is to declare variables with extern specifier in .h file and define them in one of .cpp files: 您应该做的是在.h文件中用extern说明符声明变量,然后在.cpp文件之一中定义它们:

myinput.h myinput.h

namespace MyInput
{
    extern const std::string par1;
    extern int testVar;
}

myinput.cpp myinput.cpp

namespace MyInput
{
    const std::string par1 = "par1";
    int testVar;
}

In C# every module automatically sees any symbol from any other module or source file it references, provided the symbol is accessible, public or internal. 在C#中,每个模块都会自动从其引用的任何其他模块或源文件中看到任何符号,只要该符号是可访问的, public或内部的即可。

In C++, however, that is not the case. 但是,在C ++中并非如此。 Even if the variable you want to access is public and global, you still need an external declaration to be able to use it. 即使您要访问的变量是公共变量和全局变量,您仍然需要一个外部声明才能使用它。 For example: 例如:

file1.cpp file1.cpp

int global = 0;

file2.cpp file2.cpp

int main()
{
    global = 1; //error: undefined symbol `global`.

    extern int global; //a declaration, not a definition
    global = 2; //ok!
}

Now, writing an extern declaration inside a function, as I just did is considered bad practice. 现在,像我刚才那样在函数内编写extern声明被认为是不好的做法。 It is better to write them globally. 最好在全局范围内编写它们。

extern int global;

int main()
{
    global = 3; //ok;
}

Then, writing the extern declaration this way is also considered bad practice, because you have to copy it in every module that needs to use the variable. 然后,以这种方式编写extern声明也被认为是不好的做法,因为您必须在需要使用该变量的每个模块中复制它。 It is better to write that in a file and #include it: 最好将其写入文件并#include

file1.h 文件1.h

extern int global;

file2.cpp file2.cpp

#include "file1.h"
int main()
{
    global = 4; //ok;
}

Then, it is also good practice to #include this .h file in the definition of the variable, so that the compiler can check that the definition and the declaration are consistent: 然后,将#include .h文件包含在变量的定义中也是一个好习惯,以便编译器可以检查定义和声明是否一致:

file1.cpp file1.cpp

#include "file1.h"
int global = 0; //ok: definition and initialization

float global; //error: type mismatch

If the declaration in the h file were not marked as external it would actually be a definition, and you could end up with multiple definitions of the same symbol, and a compiler or linker error. 如果h文件中的声明未标记为external则实际上是一个定义,您可能最终得到同一符号的多个定义,以及编译器或链接器错误。

Remember that #include does not do any magic under the hood, it is just a textual inclusion of the referred file. 请记住, #include#include并没有做任何魔术,它只是引用文件的文本包含。 The magic is actually in the linker, but that's another story... 魔术实际上在链接器中,但这是另一回事了……

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM