在不使用类的情况下在头文件或 cpp 文件中定义私有变量?

Define a private variable in a header file or cpp file without using class?

提问人:Junyang Liu 提问时间:9/18/2023 更新时间:9/19/2023 访问量:133

问:

嗨,我有一个问题,在不使用类的情况下,有没有其他方法可以定义只能在模块内部看到的“私有”变量,这样当我们将不同的模块包含到文件中时,不同模块中具有相同名称的变量就不会冲突?

我知道解决这个问题的最简单方法是使用不同的名称,但我实际上是将 fortran 代码翻译成 C++,除非必要,否则我真的不想更改名称。

我不想使用类的原因是,它实际上是一个大模块,有很多很多变量。在一个类中有这么多私有变量对我来说很奇怪。

谢谢!

我认为头文件中的变量无论如何都是公开的,因为当您将一个头文件包含在另一个文件中时,您实际上将所有内容复制到后面的文件中。基于这个想法,我尝试将那些“应该是私有的”变量从头文件移动到相应的 cpp 文件。但仍然不起作用。

谢谢!

C++ 变量 私有

评论

1赞 NathanOliver 9/18/2023
将变量放在 CPP 文件中是使全局变量私有化的规范方法。到那个 TU。我们能得到一个你想做什么的代码示例吗?
2赞 πάντα ῥεῖ 9/18/2023
是的,看看 c 或匿名结构来隐藏这些。static
0赞 πάντα ῥεῖ 9/18/2023
@NathanOliver这不会对链接器隐藏它
1赞 Sam Varshavchik 9/18/2023
如果你打开你的高级 C++ 教科书,看到解释匿名命名空间的章节,你会发现你正在尝试做什么的完整解释。
1赞 Peter 9/18/2023
还可以将变量放在匿名(未命名)命名空间中。每个编译单元(大致上意味着每个源文件)都可以有自己的匿名命名空间,该命名空间定义其他编译单元无法看到的变量。.cpp

答:

0赞 tbxfreeware 9/19/2023 #1
在头文件中使用命名命名空间

假设并包含来自两个 Fortran 模块的名称。module1.hmodule2.h

如果这些标头都包含在同一个文件中,则任何重复的名称都将在编译时导致重复的定义错误。.cpp

一个简单的解决方法是将这些名称放在命名命名空间中。

在头文件中,应声明每个名称。这告诉编译器声明不是定义声明。这些将被放置在文件中。extern.cpp

// module1.h
#ifndef module1_H
#define module1_H
namespace mod1
{
    extern double x, y, z;
    extern int n;
}
#endif
// module2.h
#ifndef module2_H
#define module2_H
namespace mod2
{
    extern double a, b, c;
    extern int n;
}
#endif

您还需要在其文件中定义每个名称。在本例中,您可能有 和 。.cppmodule1.cppmodule2.cpp

文件中的定义会导致为先前在头文件中声明的名称分配存储空间。.cppextern

// module1.cpp
namespace mod1
{
    double x, y, z;
    int n;
}
// module2.cpp
namespace mod2
{
    double a, b, c;
    int n;
}

当其中一个标头包含在文件中时,必须使用作用域解析运算符 (::) 以及命名空间的名称来引用其变量。.cpp

// main.cpp
#include "module1.h"
#include "module2.h"
int main()
{
    mod1::n = 0;
    mod2::n = 1;
    mod2::a = 3.14;
    // ...
    return 0;
}
在文件中使用匿名命名空间.cpp

如果所需的名称可以放在单独的文件中,并且不需要出现在头文件中,则可以省去命名命名空间。相反,名称应放置在文件的匿名命名空间中。.cpp.cpp

在匿名命名空间中定义的名称不会导出到链接器。它们具有静态链接,只能在它们首次出现的翻译单元中使用。这可能是 OP 中提到的“私有”变量的最佳近似值。

// module3.cpp
namespace 
{
    double x, y, z;
    int n;
}
void funcA()
{
    x = 3.14;
    n = 0;
    // ...
}
// module4.cpp
namespace 
{
    double a, b, c;
    int n;
}
void funcB()
{
    a = 2.7;
    n = 1;
    // ...
}
使用 C++20 中的模块

C++ 模块可能是处理此问题的最佳方法。除非您明确指定应导出模块中定义的名称,否则不会导出它们。因此,您可以将多个模块导入到同一个翻译单元(即“文件”)中,而不必担心名称冲突。

然而,模块仍然相对较新,并且可能很挑剔。这就是为什么我没有发布使用它们的示例。