Gor*_*son 172 c++ static private static-constructor initializer
我想要一个具有私有静态数据成员的类(包含所有字符az的向量).在java或C#中,我可以创建一个"静态构造函数",它将在我创建类的任何实例之前运行,并设置类的静态数据成员.它只运行一次(因为变量是只读的,只需要设置一次),因为它是类的一个函数,它可以访问它的私有成员.我可以在构造函数中添加代码来检查向量是否已初始化,如果不是,则初始化它,但是这会引入许多必要的检查,并且似乎不是问题的最佳解决方案.
我想到,因为变量只是只读的,所以它们只能是公共的静态const,所以我可以在类外面设置它们,但是再一次,它看起来有点像丑陋的黑客.
如果我不想在实例构造函数中初始化它们,是否可以在类中拥有私有静态数据成员?
Dan*_*ker 178
要获得静态构造函数的等价物,您需要编写一个单独的普通类来保存静态数据,然后创建该普通类的静态实例.
class StaticStuff
{
std::vector<char> letters_;
public:
StaticStuff()
{
for (char c = 'a'; c <= 'z'; c++)
letters_.push_back(c);
}
// provide some way to get at letters_
};
class Elsewhere
{
static StaticStuff staticStuff; // constructor runs once, single instance
};
Run Code Online (Sandbox Code Playgroud)
EFr*_*aim 80
好吧,你可以拥有
class MyClass
{
public:
static vector<char> a;
static class _init
{
public:
_init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
} _initializer;
};
Run Code Online (Sandbox Code Playgroud)
不要忘记(在.cpp中)这个:
vector<char> MyClass::a;
MyClass::_init MyClass::_initializer;
Run Code Online (Sandbox Code Playgroud)
程序仍将在没有第二行的情况下链接,但初始化程序不会被执行.
emk*_*y08 24
由于C++ 11,你可以用lambda表达式来直接初始化静态类成员.您不再需要使用任何变通办法.
头文件:
class MyClass {
static const vector<char> letters;
static const size_t letterCount;
};
Run Code Online (Sandbox Code Playgroud)
源文件:
// Initialize MyClass::letters by using a lambda expression.
const vector<char> MyClass::letters = [] {
vector<char> letters;
for (char c = 'a'; c <= 'z'; c++)
letters.push_back(c);
return letters;
}();
// The initialization order of static members is defined by the order of
// definition within the source file, so we can access MyClass::letters here.
const size_t MyClass::letterCount = letters.size();
Run Code Online (Sandbox Code Playgroud)
此模式是静态构造函数的完全替代:
Ant*_*Ant 19
在.h文件中:
class MyClass {
private:
static int myValue;
};
Run Code Online (Sandbox Code Playgroud)
在.cpp文件中:
#include "myclass.h"
int MyClass::myValue = 0;
Run Code Online (Sandbox Code Playgroud)
小智 14
这是另一种类似于Daniel Earwicker的方法,也使用了Konrad Rudolph的朋友类建议.这里我们使用内部私有友好实用程序类来初始化主类的静态成员.例如:
头文件:
class ToBeInitialized
{
// Inner friend utility class to initialize whatever you need
class Initializer
{
public:
Initializer();
};
friend class Initializer;
// Static member variables of ToBeInitialized class
static const int numberOfFloats;
static float *theFloats;
// Static instance of Initializer
// When this is created, its constructor initializes
// the ToBeInitialized class' static variables
static Initializer initializer;
};
Run Code Online (Sandbox Code Playgroud)
实施文件:
// Normal static scalar initializer
const int ToBeInitialized::numberOfFloats = 17;
// Constructor of Initializer class.
// Here is where you can initialize any static members
// of the enclosing ToBeInitialized class since this inner
// class is a friend of it.
ToBeInitialized::Initializer::Initializer()
{
ToBeInitialized::theFloats =
(float *)malloc(ToBeInitialized::numberOfFloats * sizeof(float));
for (int i = 0; i < ToBeInitialized::numberOfFloats; ++i)
ToBeInitialized::theFloats[i] = calculateSomeFancyValue(i);
}
Run Code Online (Sandbox Code Playgroud)
这种方法的优点是可以将Initializer类完全隐藏在外部世界中,从而保持类中包含的所有内容的初始化.
bit*_*ise 11
Test::StaticTest() 在全局静态初始化期间只调用一次.
调用者只需要向要作为其静态构造函数的函数添加一行.
static_constructor<&Test::StaticTest>::c;c在全局静态初始化期间强制初始化.
template<void(*ctor)()>
struct static_constructor
{
struct constructor { constructor() { ctor(); } };
static constructor c;
};
template<void(*ctor)()>
typename static_constructor<ctor>::constructor static_constructor<ctor>::c;
/////////////////////////////
struct Test
{
static int number;
static void StaticTest()
{
static_constructor<&Test::StaticTest>::c;
number = 123;
cout << "static ctor" << endl;
}
};
int Test::number;
int main(int argc, char *argv[])
{
cout << Test::number << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
无需init()功能,std::vector可以从一个范围创建:
// h file:
class MyClass {
static std::vector<char> alphabet;
// ...
};
// cpp file:
#include <boost/range.hpp>
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
std::vector<char> MyClass::alphabet( boost::begin( ::alphabet ), boost::end( ::alphabet ) );
Run Code Online (Sandbox Code Playgroud)
但请注意,类类型的静态会导致库中出现问题,因此应避免使用它们.
C++ 11更新
从C++ 11开始,您可以这样做:
// cpp file:
std::vector<char> MyClass::alphabet = { 'a', 'b', 'c', ..., 'z' };
Run Code Online (Sandbox Code Playgroud)
它在语义上等同于原始答案中的C++ 98解决方案,但是您不能在右侧使用字符串文字,因此它并不完全优越.但是,如果有任何其它类型的比的向量char,wchar_t,char16_t或char32_t(数组其可以写为字符串)时,C++ 11版本将严格除去样板代码而不引入其它语法,相比于C++ 98版.
静态构造函数的概念是在他们从C++中的问题中学习之后在Java中引入的.所以我们没有直接的等价物.
最好的解决方案是使用可以显式初始化的POD类型.
或者使静态成员成为具有自己的构造函数的特定类型,该构造函数将正确初始化它.
//header
class A
{
// Make sure this is private so that nobody can missues the fact that
// you are overriding std::vector. Just doing it here as a quicky example
// don't take it as a recomendation for deriving from vector.
class MyInitedVar: public std::vector<char>
{
public:
MyInitedVar()
{
// Pre-Initialize the vector.
for(char c = 'a';c <= 'z';++c)
{
push_back(c);
}
}
};
static int count;
static MyInitedVar var1;
};
//source
int A::count = 0;
A::MyInitedVar A::var1;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
151612 次 |
| 最近记录: |