无论如何,我可以修改此代码示例
#include <stdlib.h>
#include <iostream>
class Base {
public:
Base() {
if(!m_initialized) {
static_constructor();
m_initialized = true;
}
}
protected:
virtual void static_constructor() {
std::cout << "Base::static_constructor()\n";
}
private:
static bool m_initialized;
};
bool Base::m_initialized = false;
class Derived : public Base {
void static_constructor() {
std::cout << "Derived::static_constructor()\n";
}
};
int main(int argc, char** argv) {
Derived d;
return(EXIT_SUCCESS);
}
这样Derived::static_constructor()
被调用而不是Base?我想初始化一堆静态变量,最合乎逻辑的地方是在类中的某个地方。
答案 0 :(得分:5)
你永远不应该从构造函数(或析构函数)调用虚函数!结果将不是“预期的”(因此您看到的结果)。为什么?因为在Derived构造函数之前调用了基础构造函数(Base)。这意味着虚拟函数可能引用的Derived中的本地数据库尚未初始化。此外,甚至可能更重要的是,vtable尚未使用Derived中的函数进行初始化,仅使用Base的成员。因此,虚函数实际上并不是虚拟的 - 它不会直到Base()完成并且Derived()被处理。
另外,执行此操作会破坏Open/Closed-principle,简而言之,“类应该打开以进行扩展,但关闭以进行修改”。您正在通过更改Base静态初始化来尝试修改其行为而不是扩展它。这在当时看起来似乎是一个好主意,但稍后它可能会咬你的屁股;)
答案 1 :(得分:4)
我从Martin V Lowis的解决方案中采用了这个解决方案。主要区别在于它使用多重继承和CRTP:
template<class T>
class StaticInitializer : public T
{
static bool initialized;
public:
StaticInitializer(){
if(!initialized){
T::static_constructor();
initialized=true;
}
}
};
template<class T> bool StaticInitializer<T>::initialized;
class Base : public StaticInitializer<Base>
{
public:
static void static_constructor() {
std::cout << "Base::static_constructor()\n";
}
};
static Base _base;
class Derived : public Base, public StaticInitializer<Derived>
{
public:
static void static_constructor() {
std::cout << "Derived::static_constructor()\n";
}
};
static Derived _derived;
StaticInitializer的每个具体子类都获得了它自己的静态构造函数初始化方法,但是你保持了真正继承的优势。
答案 2 :(得分:3)
您可以避免使用模板类重复布尔变量。声明模板的实例,其构造函数将运行静态初始化程序。使实例成为静态,以便包含头文件将自动声明一个静态对象。
#include <iostream>
using namespace std;
template<class T>
class StaticInitializer{
static bool initialized;
public:
StaticInitializer(){
if(!initialized){
T::static_constructor();
initialized=true;
}
}
};
template<class T> bool StaticInitializer<T>::initialized;
class Base{
public:
static void static_constructor() {
std::cout << "Base::static_constructor()\n";
}
};
static StaticInitializer<Base> _base;
class Derived{
public:
static void static_constructor() {
std::cout << "Derived::static_constructor()\n";
}
};
static StaticInitializer<Derived> _derived;
int main()
{}
答案 3 :(得分:0)
我建议这个解决方案:
#include <cstdlib>
#include <iostream>
class Object {
public:
Object() {
std::cout << m_var << std::endl;
}
private:
static int m_var, init_var();
};
int Object::init_var() {
return 5;
}
int Object::m_var = Object::init_var();
int main(int argc, char** argv) {
Object o;
return(EXIT_SUCCESS);
}
这种方式m_var
只被初始化一次,并且我将所有构造代码保留在类中。