我想为一个类(在这种情况下是一个形状工厂)有一个私有静态常量 .
我想要有类似的东西 .
class A {
private:
static const string RECTANGLE = "rectangle";
}
不幸的是,我从C(g)编译器中得到了各种错误,例如:
ISO C禁止成员'RECTANGLE'的初始化非整数类型'std :: string'的静态数据成员的无效类内初始化错误:使'RECTANGLE'静态
这告诉我,这种成员设计不符合标准 . 如何在不必使用#define指令的情况下拥有私有文字常量(或者可能是公共的)(我想避免数据全局性的丑陋!)
任何帮助表示赞赏 .
11 回答
当前标准仅允许静态常量积分类型的这种初始化 . 所以你需要像AndreyT解释的那样做 . 但是,这将通过new member initialization syntax在下一个标准中提供 .
您必须在类定义之外定义静态成员,并在那里提供初始化程序 .
第一
然后
您最初尝试使用的语法(类定义中的初始化程序)仅允许使用整数和枚举类型 .
在C 17中,您可以使用内联变量:
请注意,这与abyss.7's answer不同:这个定义了一个实际的
std::string
对象,而不是const char*
类静态变量可以在头文件中声明,但必须在.cpp文件中定义 . 这是因为静态变量只能有一个实例,并且编译器无法决定在哪个生成的目标文件中放置它,因此您必须做出决定 .
为了使用C 11中的声明来保持静态值的定义,可以使用嵌套的静态结构 . 在这种情况下,静态成员是一个结构,必须在.cpp文件中定义,但值在 Headers 中 .
而不是初始化单个成员,整个静态结构在.cpp中初始化:
可以使用访问这些值
或 - 因为成员是私人的,并且只能用于A - with
注意,该解决方案仍然存在静态变量的初始化顺序的问题 . 当静态值用于初始化另一个静态变量时,第一个静态变量可能尚未初始化 .
在这种情况下,静态变量头将包含{“" } or { " .h ", " .hpp”},具体取决于链接器创建的初始化顺序 .
如@ abyss.7所述,如果可以在编译时计算变量的值,也可以使用
constexpr
. 但是如果你使用static constexpr const char*
声明你的字符串并且你的程序使用std::string
,否则将会产生开销,因为每次使用这样的常量时都会创建一个新的std::string
对象:你可以选择上面提到的
const char*
解决方案,但是如果你一直需要字符串,那么你将会有很多开销 .另一方面,静态字符串需要动态初始化,因此如果要在另一个全局/静态变量的初始化期间使用其值,则可能会出现初始化顺序问题 . 为了避免这种情况,最便宜的是通过getter访问静态字符串对象,它会检查您的对象是否已初始化 .
记得只使用
A::getS()
. 因为任何线程只能由main()
启动,并且A_s_initialized
在main()
之前初始化,所以即使在多线程环境中也不需要锁定 .A_s_initialized
默认为0(在动态初始化之前),因此如果在初始化s之前使用getS()
,则可以安全地调用init函数 .顺便说一句,在上面的答案中:“static const std :: string RECTANGLE()const”,静态函数不能
const
因为它们无论如何都无法改变状态(没有这个指针) .快进到2018年和C17 .
不要使用std :: string,请使用std :: string_view文字
请注意'constexpr'贝娄 . 这也是一个"compile time"机制 .
没有内联并不意味着重复
没有必要的cpp文件
static_assert'仅在编译时工作'
};
以上是适当的法律标准C公民 . 它可以轻松地参与任何和所有std ::算法,容器,实用程序等 . 例如:
享受标准C
在C 11中,您现在可以做到:
这只是额外的信息,但是如果你真的想在头文件中使用字符串,请尝试以下方法:
虽然我怀疑这是推荐的 .
这是限制 . 因此,在这种情况下,您需要在类外定义变量 . 请参阅@AndreyT的回答
内部类定义只能声明静态成员 . 它们必须在课堂之外定义 . 对于编译时积分常量,该标准使您可以"initialize"成员的例外 . 但它仍然不是一个定义 . 例如,如果没有定义,那么获取地址是行不通的 .
我看到了使用std :: string而不是常量char char []的好处 . std :: string很好,除了它需要动态初始化 . 所以,如果你写的东西像
在命名空间范围内,foo的构造函数将在执行main启动之前运行,此构造函数将在堆内存中创建常量“hello”的副本 . 除非你真的需要RECTANGLE成为std :: string,否则你也可以写
那里!没有堆分配,没有复制,没有动态初始化 .
干杯,s .
可能就是:
要么