来自Java背景,我习惯于创建类A的概念,然后创建类B来保存类A的特定静态实例,以在整个程序中使用。一些示例Java代码:
public class Color {
public int r;
public int g;
public int b;
public Color(int r, int g, int b) {
this.r = r;
this.g = g;
this.b = b;
}
}
public class Colors {
public static final Color WHITE = new Color(255, 255, 255);
public static final Color BLACK = new Color(0, 0, 0);
}
我尝试了class Color
,struct Colors
名为colors
但我收到了链接器错误,因为colors
在我包含的每个文件中都会重新实现。在C ++中执行此操作的最佳方法是什么?或者我试图以错误的方式解决问题?
答案 0 :(得分:0)
假设您的问题实际上是您提出的问题,这可能是实现它的最简单方法:
struct Color
{
int r, g, b;
Color(int r, int g, int b)
{
this->r = r;
this->g = g;
this->b = b;
}
static Color WHITE() { return {255, 255, 255}; }
static Color BLACK() { return {0, 0, 0}; }
};
如果由于某种原因需要能够引用静态对象(即每个命名颜色应该只有一个静态对象实例),您可以在标题(Colors.h
)中声明它们并初始化它们在相关的编译单元(Colors.cpp
)中,但这有点麻烦,也意味着编译器无法内联/常量折叠等编译时间常数(至少没有链接时优化)。如果常量发生变化,它确实可以保护您免受包含Colors.h
的文件的重新编译。
这种方法是一个(并不是更好)中间地带,每个颜色仍有一个静态对象实例,但你可以将它保留在标题中:https://godbolt.org/g/13krNc
但请注意,尽管进行了优化,但编译器无法确定bar()
应始终返回255
。相反,它必须检查每次调用是否已经初始化静态常量,如果没有,则初始化它们(这需要锁定线程安全!)。
答案 1 :(得分:-2)
在C ++中,include是一个实际的包含。这意味着,与Java导入相反,代码实际上是复制的。
现在多次包含文件时,您会多次出现代码。这就是为什么你需要保护你的标题代码不被复制两次。
解决方案1:将以下内容写为头文件的第一行:
#pragma once
解决方案2(更便携且广泛推荐):
#ifndef MYHEADERFILENAME_H
#define MYHEADERFILENAME_H
// your header code goes here
#endif /* MYHEADERFILENAME_H */
关于你的问题的更多想法:
不要使用类来封装constexpr值。这在C ++中不是必需的。在Java中,不可能有类外的东西,但在C ++中,这是完全合法的。只需声明您的符号并在源文件 outside 类中定义它。但是,您应该在自己的命名空间中声明它,以避免名称冲突。
也许枚举类scoped enumeration更接近你真正想要的东西。