我经常需要定义与类关联的字符串常量。 例如 XML 属性、默认文件名等等。
在Java中,我会简单地定义类似的东西
public static final String KEY = "attribute";
在类或接口内。
在C++中,以下内容将无法编译:
class Example {
public:
static const std::string KEY = "attribute";
}
相反,我必须写:
class Example {
public:
static const std::string KEY;
}
const std::string Example::KEY = "attribute";
这是我绝对想避免的事情,因为它的冗余和冗长。
到目前为止,我发现的最佳解决方案是使用函数:
class Example {
public:
static std::string KEY() const { return "attribute"; }
}
这也提供了一些封装和灵活性。但是,仅使用函数来定义常量似乎有点奇怪。
所以我的问题是,这种解决方案是否有重大缺点,如果是,还有什么更好的选择?
在 c++03 中,最好的选择是按照你正在使用的方式使用函数,这很尴尬。唯一的问题是,当您可以免费归还const char* const
时,您为什么要归还std::string
并支付其建筑价格。
如果出于某种原因,您真的必须const std::string
(再次,它违背了我的整个经验,因此您可能需要重新考虑)以下代码在效率方面效果最好(您当前的版本在每次调用时都调用std::string
构造函数!
class Example {
public:
static const std::string& key() {
static const std::string the_key = "That's my key!";
return the_key;
}
}
在 c++11 中,您有几个选项,其中我认为最好的constexpr
:
class Example {
public:
static constexpr const char* const KEY = "TheKey";
}
另一种选择是就地初始化 const 字符串,但为什么要为此付出代价呢?
class Example {
public:
static const std::string KEY = "TheKey";
};
而在 Java 中,类及其静态成员与类一起加载——这意味着类作为一个单元或作为 JAR 的一部分是可替换的——C++它不会那样做。如果你把东西放在标题中,你会付出无法替换它们的代价,直到你重新编译包含它们的所有内容。
这就是为什么惯用的——也是最有益的——方法是在标头中声明它们,并在它所属的地方提供实现,在翻译单元中,它可以链接到任何其他二进制文件。所以考虑重新调整你的观点(我从 C# 转到 C++ 所以我不止一次遇到这种情况)。
但是你根本不需要走字符串的道路。您可以创建枚举,这是一种更优雅且类型安全的方式来实现此目的。使用枚举(特别是枚举类),您不能只传入错误的字符串。您必须传入一组有效值之一。
例如,您可以执行以下操作:
class Example {
public:
enum class Attributes {
One,
Two,
// ...
};
}
然后,当它很重要时,当你对什么是什么有本地知识时,你可以将枚举值映射到实际字符串或实际实现所需的内容。
您可以定义类的构造函数,以便每次使用该类时,构造函数都会自动将值"属性分配给字符串"
class Example {
public:
static const std::string KEY;
Example()
{
KEY="Attribute";
}
};