我认为既然变量是只读的,它们可以被声明为公共静态常量,这样我就可以在类外部设置它们一次。但再次强调,这似乎仍是一种丑陋的hack方法。
如果我不想在实例构造函数中初始化它们,那么有可能创建一个私有静态数据成员吗?
要获得静态构造函数的等效功能,您需要编写一个单独的普通类来保存静态数据,然后创建该普通类的静态实例。
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
};
好的,你可以拥有
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;
即使没有第二行,该程序仍将链接,但初始化程序将不会被执行。
MyClass::a.push_back(i)
而不是 a.push_back(i)
吧? - Neel Basu_initializer
是 MyClass
的一个子对象。子对象按照以下顺序初始化:虚拟基类子对象按深度优先,从左往右的顺序(但每个不同的子对象只初始化一次);然后是普通基类子对象,按深度优先,从左往右的顺序;最后是成员子对象,按声明顺序排列。因此,如果 _initialiser
中的代码只涉及到在它之前声明的成员,则使用 EFraim 的策略是安全的。 - j_random_hacker自C++11以来,您可以简单地使用lambda表达式来初始化静态类成员。您不再需要使用任何辅助类或解决方法。
头文件:
class MyClass {
static const vector<char> letters;
};
源文件:
// Initialize MyClass::letters with all letters from 'a' to 'z'.
const vector<char> MyClass::letters = [] {
vector<char> letters;
for (char c = 'a'; c <= 'z'; c++)
letters.push_back(c);
return letters;
}();
关于静态初始化顺序的注意事项:
如果多个静态类成员必须按照某个特定顺序初始化,这种方法也适用。由于静态成员始终按照源文件中定义的完全相同的顺序初始化,因此您只需确保在源文件中以正确的顺序编写初始化即可。
try catch
块中。 - emkey08class MyClass {
private:
static int myValue;
};
在 .cpp 文件中:#include "myclass.h"
int MyClass::myValue = 0;
这里提供一种与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;
};
实现文件:
// 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);
}
采用这种方法的优点是完全隐藏了初始化器类,使一切都包含在要初始化的类内部。
ToBeInitialized::Initializer::Initializer()
,因此需要在实现文件中添加ToBeInitialized::Initializer ToBeInitialized::initializer;
。我从您的想法和EFraim的想法中借鉴了一些东西,它完全按照我的要求工作并且看起来很干净。谢谢,伙计。 - Andrew LarssonTest::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;
}
不需要 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++98版本相比,C++11版本将严格消除样板代码而不引入其他语法。
//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;
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;
}
};
我猜,简单的解决方案如下:
//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;
}