C ++静态常量string(类成员)
我想有一个类的私有静态常量(在这种情况下形状工厂)。 我想有这样的事情。
class A { private: static const string RECTANGLE = "rectangle"; }
不幸的是,我得到了来自C ++(g ++)编译器的各种错误,比如:
ISO C ++禁止成员'RECTANGLE'的初始化
非整型types“std :: string”的静态数据成员的无效类内初始化
错误:使“RECTANGLE”静态
这告诉我这种会员devise不符合标准。 你怎么有一个私人文字常量(或者也许是公共的),而不必使用#定义指令(我想避免丑陋的数据全球性!)
任何帮助表示赞赏。 谢谢。
您必须在类定义之外定义静态成员,并在其中提供初始化程序。
第一
// In a header file (if it is in a header file in your case) class A { private: static const string RECTANGLE; };
接着
// In one of the implementation files const string A::RECTANGLE = "rectangle";
您最初尝试使用的语法(类定义中的初始值设定项)只允许使用整型和枚举types。
在C ++ 11中,你现在可以做到:
class A { private: static constexpr const char* STRING = "some useful string constant"; };
在类的定义里面,你只能声明静态成员。 他们必须在class级之外定义 。 对于编译时积分常量,这个标准使得你可以“初始化”成员的例外。 虽然这还不是一个定义。 举个例子,如果没有定义,这个地址就行不通了。
我想提一下,我没有看到使用std :: string比const char [] 常量的好处。 std :: string是很好的,但它需要dynamic初始化。 所以,如果你写了类似的东西
const std::string foo = "hello";
在命名空间范围内,foo的构造函数将在主启动执行之前运行,此构造函数将在堆内存中创build一个常量“hello”的副本。 除非你真的需要使用RECTANGLE作为std :: string,否则你也可以写
// class definition with incomplete static member could be in a header file class A { static const char RECTANGLE[]; }; // this needs to be placed in a single translation unit only const char A::RECTANGLE[] = "rectangle";
那里! 没有堆分配,没有复制,没有dynamic初始化。
干杯。
这只是额外的信息,但如果你真的想在一个头文件中的string,请尝试像这样:
class foo { public: static const std::string& RECTANGLE(void) { static const std::string str = "rectangle"; return str; } };
虽然我怀疑这是build议。
要使用类内初始化语法,常量必须是由常量expression式初始化的整型或枚举types的静态常量。
这是限制。 因此,在这种情况下,您需要在类之外定义variables。 请参阅@AndreyT的答案
可能只是做:
static const std::string RECTANGLE() const { return "rectangle"; }
要么
#define RECTANGLE "rectangle"
目前的标准只允许静态常量整型的初始化。 所以你需要做AndreyT解释。 但是,这将通过新的成员初始化语法在下一个标准中提供。
你可以去上面提到的const char*
解决scheme,但是如果你总是需要string的话,你将会有很多开销。
另一方面,静态string需要dynamic初始化,因此如果你想在另一个全局/静态variables初始化时使用它的值,你可能会遇到初始化顺序的问题。 为了避免这种情况,最便宜的是通过一个getter访问静态string对象,该对象检查对象是否被初始化。
//in a header class A{ static string s; public: static string getS(); }; //in implementation string A::s; namespace{ bool init_A_s(){ A::s = string("foo"); return true; } bool A_s_initialized = init_A_s(); } string A::getS(){ if (!A_s_initialized) A_s_initialized = init_A_s(); return s; }
请记住只使用A::getS()
。 因为任何线程只能由main()
启动,并且A_s_initialized
在main()
之前初始化,所以即使在multithreading环境中也不需要locking。 A_s_initialized
默认为0(在dynamic初始化之前),所以如果在s被初始化之前使用getS()
,则可以安全地调用init函数。
顺便说一句,在上面的答案:“ static const std :: string RECTANGLE()const ”,静态函数不能是const
因为如果有任何对象(没有这个指针)它们不能改变状态。
类静态variables可以在头中声明 ,但必须在.cpp文件中定义 。 这是因为只能有一个静态variables的实例,而编译器不能决定在哪个生成的目标文件中放置它,所以你必须做出决定。
为了使用C ++ 11中的声明保留静态值的定义,可以使用嵌套的静态结构。 在这种情况下,静态成员是一个结构,必须在一个.cpp文件中定义,但值在标题中。
class A { private: static struct _Shapes { const std::string RECTANGLE {"rectangle"}; const std::string CIRCLE {"circle"}; } shape; };
而不是初始化个别成员整个静态结构在.cpp中初始化:
A::_Shapes A::shape;
值是通过访问
A::shape.RECTANGLE;
或者 – 因为这些成员是私人的,只能用于A – with
shape.RECTANGLE;
请注意,这个解决scheme仍然存在静态variables初始化顺序的问题。 当一个静态值被用来初始化另一个静态variables时,第一个可能还没有被初始化。
// file.h class File { public: static struct _Extensions { const std::string h{ ".h" }; const std::string hpp{ ".hpp" }; const std::string c{ ".c" }; const std::string cpp{ ".cpp" }; } extension; }; // file.cpp File::_Extensions File::extension; // module.cpp static std::set<std::string> headers{ File::extension.h, File::extension.hpp };
在这种情况下,根据链接器创build的初始化顺序,静态variables标题将包含{“”}或{“.h”,“.hpp”}。
正如@ abyss.7所提到的那样,如果variables的值可以在编译时计算,那么也可以使用constexpr
。 但是,如果你使用static constexpr const char*
声明你的string,并且你的程序使用了std::string
否则会有开销,因为每当你使用这样一个常量时就会创build一个新的std::string
对象:
class A { public: static constexpr const char* STRING = "some value"; }; void foo(const std::string& bar); int main() { foo(A::STRING); // a new std::string is constructed and destroyed. }