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_initializedmain()之前初始化,所以即使在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. }