C++中的静态构造函数?我需要初始化私有静态对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1197106/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
static constructors in C++? I need to initialize private static objects
提问by Gordon Gustafson
I want to have a class with a private static data member (a vector that contains all the characters a-z). In java or C#, I can just make a "static constructor" that will run before I make any instances of the class, and sets up the static data members of the class. It only gets run once (as the variables are read only and only need to be set once) and since it's a function of the class it can access its private members. I could add code in the constructor that checks to see if the vector is initialized, and initialize it if it's not, but that introduces many necessary checks and doesn't seem like the optimal solution to the problem.
我想要一个带有私有静态数据成员的类(一个包含所有字符 az 的向量)。在 java 或 C# 中,我可以创建一个“静态构造函数”,在创建类的任何实例之前运行它,并设置类的静态数据成员。它只运行一次(因为变量是只读的并且只需要设置一次)并且因为它是类的一个函数,所以它可以访问它的私有成员。我可以在构造函数中添加代码来检查向量是否已初始化,如果未初始化则对其进行初始化,但这引入了许多必要的检查,并且似乎不是问题的最佳解决方案。
The thought occurs to me that since the variables will be read only, they can just be public static const, so I can set them once outside the class, but once again, it seems sort of like an ugly hack.
我突然想到,由于变量将是只读的,它们可以只是 public static const,所以我可以在类外设置它们一次,但再一次,这似乎有点像一个丑陋的黑客。
Is it possible to have private static data members in a class if I don't want to initialize them in the instance constructor?
如果我不想在实例构造函数中初始化它们,是否可以在类中拥有私有静态数据成员?
回答by Daniel Earwicker
To get the equivalent of a static constructor, you need to write a separate ordinary class to hold the static data and then make a static instance of that ordinary class.
要获得静态构造函数的等效项,您需要编写一个单独的普通类来保存静态数据,然后创建该普通类的静态实例。
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
};
回答by EFraim
Well you can have
那么你可以有
class MyClass
{
public:
static vector<char> a;
static class _init
{
public:
_init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
} _initializer;
};
Don't forget (in the .cpp) this:
不要忘记(在 .cpp 中)这个:
vector<char> MyClass::a;
MyClass::_init MyClass::_initializer;
The program will still link without the second line, but the initializer will not be executed.
程序仍然会在没有第二行的情况下进行链接,但不会执行初始化程序。
回答by emkey08
C++11 solution
C++11 解决方案
Since C++11, you can simply use lambda expressionsto initialize static class members. This even works if you need to impose an order of construction between the various static members, or if you have static members which are const
.
从 C++11 开始,您可以简单地使用lambda 表达式来初始化静态类成员。如果您需要在各种静态成员之间强加构造顺序,或者如果您有静态成员是const
.
Header file:
头文件:
class MyClass {
static const vector<char> letters;
static const size_t letterCount;
};
Source file:
源文件:
// 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();
回答by Ant
In the .h file:
在 .h 文件中:
class MyClass {
private:
static int myValue;
};
In the .cpp file:
在 .cpp 文件中:
#include "myclass.h"
int MyClass::myValue = 0;
回答by Douglas Mandell
Here is another approach similar to Daniel Earwicker's, also using Konrad Rudolph's friend class suggestion. Here we use an inner private friend utility class to initialize the static members of your main class. For example:
这是类似于 Daniel Earwicker 的另一种方法,也使用了 Konrad Rudolph 的朋友班建议。这里我们使用内部私有朋友实用程序类来初始化主类的静态成员。例如:
Header file:
头文件:
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;
};
Implementation file:
实现文件:
// 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);
}
This approach has the advantage of completely hiding the Initializer class from the outside world, keeping everything contained within the class to be initialized.
这种方法的优点是对外界完全隐藏 Initializer 类,保持类中包含的所有内容都被初始化。
回答by CuriousGeorge
Test::StaticTest()
is called exactly once during global static initialization.
Test::StaticTest()
在全局静态初始化期间只调用一次。
Caller only has to add one line to the function that is to be their static constructor.
调用者只需向将成为其静态构造函数的函数添加一行。
static_constructor<&Test::StaticTest>::c;
forces initialization of c
during global static initialization.
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;
}
回答by Marc Mutz - mmutz
No need for an init()
function, std::vector
can be created from a range:
不需要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 ) );
Note, however, that statics of class type cause trouble in libraries, so they should be avoided there.
但是请注意,类类型的静态变量会在库中造成麻烦,因此应避免使用它们。
C++11 Update
C++11 更新
As of C++11, you can do this instead:
从 C++11 开始,您可以改为这样做:
// cpp file:
std::vector<char> MyClass::alphabet = { 'a', 'b', 'c', ..., 'z' };
It's semantically equivalent to the C++98 solution in the original answer, but you can't use a string literal on the right-hand-side, so it's not completely superior. However, if you have a vector of any other type than char
, wchar_t
, char16_t
or char32_t
(arrays of which can be written as string literals), the C++11 version will strictly remove boilerplate code without introducing other syntax, compared to the C++98 version.
它在语义上等同于原始答案中的 C++98 解决方案,但您不能在右侧使用字符串文字,因此它并不完全优越。但是,如果您有任何其他类型的向量而不是char
, wchar_t
, char16_t
or char32_t
(其数组可以写为字符串文字),与 C++98 相比,C++11 版本将严格删除样板代码而不引入其他语法版本。
回答by Martin York
The concept of static constructors was introduced in Java after they learned from the problems in C++. So we have no direct equivalent.
静态构造函数的概念是Java从C++中学习到的问题后引入的。所以我们没有直接的等价物。
The best solution is to use POD types that can be initialised explicitly.
Or make your static members a specific type that has its own constructor that will initialize it correctly.
最好的解决方案是使用可以显式初始化的 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;
回答by Martin York
When trying to compile and useclass Elsewhere
(from Earwicker's answer) I get:
尝试编译和使用类时Elsewhere
(来自Earwicker 的回答),我得到:
error LNK2001: unresolved external symbol "private: static class StaticStuff Elsewhere::staticStuff" (?staticStuff@Elsewhere@@0VStaticStuff@@A)
It seems is not possible to initialize static attributes of non-integer types without putting some code outside the class definition (CPP).
如果不将一些代码放在类定义 (CPP) 之外,就不可能初始化非整数类型的静态属性。
To make that compile you can use "a static method with a static local variable inside" instead. Something like this:
要进行编译,您可以改用“内部带有静态局部变量的静态方法”。像这样的东西:
class Elsewhere
{
public:
static StaticStuff& GetStaticStuff()
{
static StaticStuff staticStuff; // constructor runs once, single instance
return staticStuff;
}
};
And you may also pass arguments to the constructor or initialize it with specific values, it is very flexible, powerfull and easy to implement... the only thing is you have a static method containing a static variable, not a static attribute... syntaxis changes a bit, but still useful. Hope this is useful for someone,
并且您还可以将参数传递给构造函数或使用特定值对其进行初始化,它非常灵活、强大且易于实现……唯一的问题是您有一个包含静态变量的静态方法,而不是静态属性……语法略有变化,但仍然有用。希望这对某人有用,
Hugo González Castro.
雨果冈萨雷斯卡斯特罗。
回答by Shubham
I guess Simple solution to this will be:
我想对此的简单解决方案是:
//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;
}