我有一个带有一些静态成员的类,并且我想运行一些代码来初始化它们(假设此代码无法转换成简单的表达式)。在Java中,我只会
class MyClass {
static int myDatum;
static {
/* do some computation which sets myDatum */
}
}
除非我弄错了,否则C ++不允许使用此类静态代码块,对吗?我应该怎么做呢?
我想要以下两个选项的解决方案:
对于第二种选择,我在想:
class StaticInitialized {
static bool staticsInitialized = false;
virtual void initializeStatics();
StaticInitialized() {
if (!staticsInitialized) {
initializeStatics();
staticsInitialized = true;
}
}
};
class MyClass : private StaticInitialized {
static int myDatum;
void initializeStatics() {
/* computation which sets myDatum */
}
};
但这是不可能的,因为C ++(目前?)不允许初始化非常量静态成员。但是,至少这可以通过表达式将静态块的问题减少到静态初始化的问题…
事实证明,我们可以实现Java样式的静态块,尽管它是在类外部而不是在类内部,即在翻译单元范围内。内幕的实现有点丑陋,但是使用起来非常优雅!
该解决方案现在有一个GitHub存储库,其中包含一个头文件:static_block.hpp
。
如果您写:
static_block {
std::cout << "Hello static block world!\n";
}
此代码将在您的之前运行main()
。您可以初始化静态变量,也可以执行其他任何操作。因此,您可以在类的.cpp
实现文件中放置这样的块。
笔记:
静态块实现涉及使用函数静态初始化的虚拟变量。您的静态块实际上是该函数的主体。为了确保我们不会与其他虚拟变量发生冲突(例如,来自另一个静态块或其他任何地方),我们需要一些宏机制。
#define CONCATENATE(s1, s2) s1##s2
#define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)
#ifdef __COUNTER__
#define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __COUNTER__)
#else
#define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __LINE__)
#endif // __COUNTER__
这是将内容组合在一起的宏工作:
#define static_block STATIC_BLOCK_IMPL1(UNIQUE_IDENTIFIER(_static_block_))
#define STATIC_BLOCK_IMPL1(prefix) \
STATIC_BLOCK_IMPL2(CONCATENATE(prefix,_fn),CONCATENATE(prefix,_var))
#define STATIC_BLOCK_IMPL2(function_name,var_name) \
static void function_name(); \
static int var_name __attribute((unused)) = (function_name(), 0) ; \
static void function_name()
笔记:
__COUNTER__
-它不是C
标准的一部分;它不支持C
。在这种情况下,以上代码__LINE__
也会使用。GCC和Clang支持__COUNTER__
。__attribute ((unused))
可被丢弃,或更换[[unused]]
,如果你有一个C ++编译器11,其不喜欢的GCC风格的未使用的扩展。main()
,但不能保证相对于其他静态初始化确切的执行时间。Live Demo
问题内容: Scala与Java的静态块等效吗? 问题答案: 伴随对象的构造函数(即主体)中的代码与Java类的静态初始化程序块中的代码 不 完全相同。在下面的示例中,我创建了A的实例,但是没有发生初始化。 要在创建类的第一个实例时触发伴随对象的构造,可以从类构造函数中访问它。 在许多情况下,差异并不重要。但是,如果您要发射导弹(或其他副作用),您可能会在意!
问题内容: 我涉足clojure,尝试确定与该通用python习语等效的clojure(和/或Lisp)有点麻烦。 习惯用法是,在python模块的底部经常有一些测试代码,然后是运行该代码的语句,例如: 这对于简单的临时测试很有用。通常,通过编写可以使用此模块,在这种情况下,从不调用它,但是在代码段的最后,也可以通过直接从命令行键入内容来运行该模块。 Clojure(和/或普通Lisp)中是否有一
问题内容: Kotlin中没有关键字。 用Kotlin 表示Java方法的最佳方法是什么? 问题答案: 您将功能放置在“伴侣对象”中。 所以像这样的java代码: 会变成 然后,您可以从Kotlin代码内部使用它,如下所示: 但是从Java代码中,您需要将其称为 (这也来自Kotlin。) 如果您不想指定位,则可以添加注释或命名伴侣类。 从文档: 类内的对象声明可以用伴随关键字标记: 可以通过仅使
问题内容: 我将Java转换为C#,并具有以下代码(请参阅JavaContext中有关其使用的讨论。一种方法可能是创建一个单独的文件/类,但是是否有C#idom保留了Java代码中的意图? 问题答案: 看看这个 http://blogs.msdn.com/oldnewthing/archive/2006/08/01/685248.aspx 我正在专门看 换句话说,Java内部类是C#无法使用的语法
问题内容: 在C / C ++(以及该家族的许多语言)中,根据条件声明和初始化变量的常用习语使用三元条件运算符: Go没有条件运算符。实现与上述相同代码的最惯用方式是什么?我来到以下解决方案,但似乎很冗长 有更好的东西吗? 问题答案: 正如指出的那样(并希望毫不奇怪),使用确实是Go 语言中进行条件处理的惯用方式。 但是,除了完整的代码块之外,还经常使用以下拼写: 并且如果您有足够重复的代码块(例
问题内容: 我将某些本机方法重写为常规Java方法。 本机方法有效地静态吗?或者是否曾经有一个隐式的“ this”参数? 谢谢! 问题答案: 就像常规Java方法一样,本机方法可以是非方法。 非本机方法接收引用,而非本机方法则接收对containg类的引用。 根据JNI规范: 本机方法参数 JNI接口指针是本机方法的第一个参数。JNI接口指针的类型为JNIEnv。第二个参数根据本机方法是静态还是静