我想有一类的私人静态数据成员(包含所有AZ字符的向量)。 在Java或C#,我可以做一个“静态构造函数”之前,我做任何类实例将运行,并设置类的静态数据成员。 它只是(因为变量是只读,只需要设置一次),并因为它是类的功能,它可以访问它的私有成员被运行一次。 我可以检查,看看如果向量被初始化构造函数添加代码,如果它不将其初始化,但引入了许多必要的检查,似乎不喜欢这个问题的最佳解决方案。
想到这里发生,我认为自变量将是只读,他们可以是公共静态常量,这样我就可以在类外设置一次他们,但再一次,这似乎有点像一个丑陋的黑客。
是否有可能有私人静态数据成员的一类,如果我不想初始化它们的构造函数?
Answer 1:
为了得到一个静态构造函数相当于,你需要写一个单独的普通类来保存静态数据,然后进行普通类的静态实例。
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
};
Answer 2:
那么你可以有
class MyClass
{
public:
static vector<char> a;
static class _init
{
public:
_init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
} _initializer;
};
不要(在的.cpp)这个忘记:
vector<char> MyClass::a;
MyClass::_init MyClass::_initializer;
该程序仍会链接,没有第二行,但初始化将不会被执行。
Answer 3:
在.h文件:
class MyClass {
private:
static int myValue;
};
在.cpp文件:
#include "myclass.h"
int MyClass::myValue = 0;
Answer 4:
C ++ 11溶液
由于C ++ 11,你可以简单地使用lambda表达式来初始化静态类成员,即使你需要施加的各种静态成员之间建设一个数量级。
头文件:
class MyClass {
static vector<char> letters;
static size_t letterCount;
};
源文件:
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 use MyClass::letters here.
size_t MyClass::letterCount = [] {
return letters.size();
}();
Answer 5:
这是另一种方法类似,丹尼尔·埃里克的,也采用康拉德·鲁道夫的友元类建议。 在这里,我们使用一个内部的私人朋友的实用工具类初始化主类的静态成员。 例如:
头文件:
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;
};
实现文件:
// 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);
}
这种方法有来自外界完全隐藏初始化类,保持包含在类内的所有内容将被初始化的优势。
Answer 6:
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;
}
Answer 7:
不需要一个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 ) );
但是请注意,在图书馆类类型作祟的是静,所以应尽量避免在那里。
C ++ 11更新
由于C ++ 11,你可以这样做,而不是:
// cpp file:
std::vector<char> MyClass::alphabet = { 'a', 'b', 'c', ..., 'z' };
这是语义上等同于原答案C ++ 98的解决方案,但你不能用一个字符串在右手边,所以它不是完全优越。 但是,如果有任何其它类型的比的矢量char
, wchar_t
, char16_t
或char32_t
(数组其可以写为字符串)时,C ++ 11版本将严格除去样板代码而不引入其它语法,相比C ++ 98版本。
Answer 8:
静态构造函数的概念在Java中被引入后,他们从C ++的问题的经验教训。 因此,我们有没有直接的等价物。
最好的解决办法是使用可以明确地进行初始化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;
Answer 9:
当试图编译和使用类Elsewhere
(由埃里克的答案 )我得到:
error LNK2001: unresolved external symbol "private: static class StaticStuff Elsewhere::staticStuff" (?staticStuff@Elsewhere@@0VStaticStuff@@A)
这似乎是不可能的初始化非整数类型的静态属性,而不把一些代码的类定义(CPP)之外。
为了让这个编译您可以使用“ 静态方法与静态局部变量内 ”代替。 事情是这样的:
class Elsewhere
{
public:
static StaticStuff& GetStaticStuff()
{
static StaticStuff staticStuff; // constructor runs once, single instance
return staticStuff;
}
};
而且你还可以传递参数给构造或特定值初始化它,它非常灵活,功能强大,易于实现...唯一的事情是你必须包含一个静态变量,而不是一个静态属性的静态方法...大成修改了一下,但还是有用的。 希望这是有用的人,
雨果·冈萨雷斯·卡斯特罗。
Answer 10:
我想简单的解决方案,这将是:
//X.h
#pragma once
class X
{
public:
X(void);
~X(void);
private:
static bool IsInit;
static bool Init();
};
//X.cpp
#include "X.h"
#include <iostream>
X::X(void)
{
}
X::~X(void)
{
}
bool X::IsInit(Init());
bool X::Init()
{
std::cout<< "ddddd";
return true;
}
// main.cpp
#include "X.h"
int main ()
{
return 0;
}
Answer 11:
只要解决了同样的伎俩。 我不得不指定辛格尔顿一个静态成员的定义。 但是,让事情变得更加复杂 - 我已经决定,我不想叫RandClass(),除非我要去使用它的构造函数...这就是为什么我不想在我的代码初始化全球单。 此外,我已经在我的情况下添加简单的接口。
下面是最终代码:
我简化代码和使用rand()函数和它的单个种子initialzer srand()函数
interface IRandClass
{
public:
virtual int GetRandom() = 0;
};
class RandClassSingleton
{
private:
class RandClass : public IRandClass
{
public:
RandClass()
{
srand(GetTickCount());
};
virtual int GetRandom(){return rand();};
};
RandClassSingleton(){};
RandClassSingleton(const RandClassSingleton&);
// static RandClass m_Instance;
// If you declare m_Instance here you need to place
// definition for this static object somewhere in your cpp code as
// RandClassSingleton::RandClass RandClassSingleton::m_Instance;
public:
static RandClass& GetInstance()
{
// Much better to instantiate m_Instance here (inside of static function).
// Instantiated only if this function is called.
static RandClass m_Instance;
return m_Instance;
};
};
main()
{
// Late binding. Calling RandClass ctor only now
IRandClass *p = &RandClassSingleton::GetInstance();
int randValue = p->GetRandom();
}
abc()
{
IRandClass *same_p = &RandClassSingleton::GetInstance();
}
Answer 12:
这里是我的埃夫拉伊姆解决方案的变体; 所不同的是,由于隐式模板实例,静态构造函数只有在创建类的实例调用,并且,在没有定义.cpp
文件需要(感谢模板实例魔法)。
在.h
文件,你必须:
template <typename Aux> class _MyClass
{
public:
static vector<char> a;
_MyClass() {
(void) _initializer; //Reference the static member to ensure that it is instantiated and its initializer is called.
}
private:
static struct _init
{
_init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
} _initializer;
};
typedef _MyClass<void> MyClass;
template <typename Aux> vector<char> _MyClass<Aux>::a;
template <typename Aux> typename _MyClass<Aux>::_init _MyClass<Aux>::_initializer;
在.cpp
文件,您可以:
void foobar() {
MyClass foo; // [1]
for (vector<char>::iterator it = MyClass::a.begin(); it < MyClass::a.end(); ++it) {
cout << *it;
}
cout << endl;
}
需要注意的是MyClass::a
被初始化仅当线[1]是存在的,因为调用(和需要的实例化)的构造,然后需要的实例_initializer
。
Answer 13:
这里的另一种方法,当载体是私有的,它包含通过使用匿名命名空间中的执行文件。 它是这样的事情是私有的,执行查找表有用:
#include <iostream>
#include <vector>
using namespace std;
namespace {
vector<int> vec;
struct I { I() {
vec.push_back(1);
vec.push_back(3);
vec.push_back(5);
}} i;
}
int main() {
vector<int>::const_iterator end = vec.end();
for (vector<int>::const_iterator i = vec.begin();
i != end; ++i) {
cout << *i << endl;
}
return 0;
}
Answer 14:
这当然并不需要像目前公认的答案(由丹尼尔·埃里克)那么复杂。 类是多余的。 有没有必要在这种情况下,一种语言的战争。
.HPP文件:
vector<char> const & letters();
CPP文件:
vector<char> const & letters()
{
static vector<char> v = {'a', 'b', 'c', ...};
return v;
}
Answer 15:
GCC报价
__attribute__((constructor))
https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
标签与该属性的静态方法,它会在模块负荷运行,main()之前。
Answer 16:
你同样定义静态成员变量定义成员方法的方式。
foo.h中
class Foo
{
public:
void bar();
private:
static int count;
};
Foo.cpp中
#include "foo.h"
void Foo::bar()
{
// method definition
}
int Foo::count = 0;
Answer 17:
要初始化一个静态变量,你只是一个源文件内这样做。 例如:
//Foo.h
class Foo
{
private:
static int hello;
};
//Foo.cpp
int Foo::hello = 1;
Answer 18:
如何创建模板来模仿C#的行为。
template<class T> class StaticConstructor
{
bool m_StaticsInitialised = false;
public:
typedef void (*StaticCallback)(void);
StaticConstructor(StaticCallback callback)
{
if (m_StaticsInitialised)
return;
callback();
m_StaticsInitialised = true;
}
}
template<class T> bool StaticConstructor<T>::m_StaticsInitialised;
class Test : public StaticConstructor<Test>
{
static std::vector<char> letters_;
static void _Test()
{
for (char c = 'a'; c <= 'z'; c++)
letters_.push_back(c);
}
public:
Test() : StaticConstructor<Test>(&_Test)
{
// non static stuff
};
};
Answer 19:
对于简单的情况下,像这里,裹静态成员函数内部静态变量是几乎一样好。 这是简单的,并且通常由编译器被优化掉。 这并不解决复杂的对象初始化顺序问题虽然。
#include <iostream>
class MyClass
{
static const char * const letters(void){
static const char * const var = "abcdefghijklmnopqrstuvwxyz";
return var;
}
public:
void show(){
std::cout << letters() << "\n";
}
};
int main(){
MyClass c;
c.show();
}
Answer 20:
这是一个解决方案?
class Foo
{
public:
size_t count;
Foo()
{
static size_t count = 0;
this->count = count += 1;
}
};
Answer 21:
静态构造可以通过使用朋友类或如下嵌套类进行仿真。
class ClassStatic{
private:
static char *str;
public:
char* get_str() { return str; }
void set_str(char *s) { str = s; }
// A nested class, which used as static constructor
static class ClassInit{
public:
ClassInit(int size){
// Static constructor definition
str = new char[size];
str = "How are you?";
}
} initializer;
};
// Static variable creation
char* ClassStatic::str;
// Static constructor call
ClassStatic::ClassInit ClassStatic::initializer(20);
int main() {
ClassStatic a;
ClassStatic b;
std::cout << "String in a: " << a.get_str() << std::endl;
std::cout << "String in b: " << b.get_str() << std::endl;
a.set_str("I am fine");
std::cout << "String in a: " << a.get_str() << std::endl;
std::cout << "String in b: " << b.get_str() << std::endl;
std::cin.ignore();
}
输出:
String in a: How are you?
String in b: How are you?
String in a: I am fine
String in b: I am fine
Answer 22:
Wow, I can't believe no one mentioned the most obvious answer, and one that most closely mimics C#'s static-constructor behavior, i.e. it doesn't get called until the first object of that type is created.
std::call_once()
is available in C++11; if you can't use that, it can be done with a static boolean class-variable, and a compare-and-exchange atomic-operation. In your constructor, see if you can atomically change the class-static flag from false
to true
, and if so, you can run the static-construction code.
For extra credit, make it a 3-way flag instead of a boolean, i.e. not run, running, and done running. Then all other instances of that class can spin-lock until the instance running the static-constructor has finished (i.e. issue a memory-fence, then set the state to "done running"). Your spin-lock should execute the processor's "pause" instruction, double the wait each time up until a threshold, etc. — pretty standard spin-locking technique.
In the absence of C++11, this should get you started.
Here's some pseudocode to guide you. Put this in your class definition:
enum EStaticConstructor { kNotRun, kRunning, kDone };
static volatile EStaticConstructor sm_eClass = kNotRun;
And this in your constructor:
while (sm_eClass == kNotRun)
{
if (atomic_compare_exchange_weak(&sm_eClass, kNotRun, kRunning))
{
/* Perform static initialization here. */
atomic_thread_fence(memory_order_release);
sm_eClass = kDone;
}
}
while (sm_eClass != kDone)
atomic_pause();
文章来源: static constructors in C++? I need to initialize private static objects