tags:

views:

257

answers:

4

Is there anyway I can modify this code example

#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);
}

So that Derived::static_constructor() gets called instead of the Base's? I want to initialize a bunch of static variables, and the most logical place to do it is somewhere in the class.

+2  A: 

You can avoid duplication of the boolean variable with a template class. Declare an instance of the of the template whose constructor will run the static initializer. Make the instance static, so that inclusion of the header file will automatically declare a static object.

#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()
{}
Martin v. Löwis
As nice as this solution is... then base and derived are of type `StaticInitializer` and I can't use their other member functions...
Mark
+5  A: 

You should never call virtual functions from the constructor (or destructor)! The result will not be as "expected" (hence the result you see). Why? Because the base constructor (Base) is called before the Derived constructor. This means that the local datamembers in Derived, which the virtual function may refer to, are not initialized yet. In addition, and maybe even more importantly, the vtable has not been initialized with functions in Derived yet, only with members from Base. Hence, the virtual function isn't really virtual yet - it won't be untill Base() completes and Derived() is processed.

Also, doing this would break the Open/Closed-principle which in short reads "classes should be open for extension, but closed for modification". You are by altering the Base static initialization trying to modify its behavior rather than extending it. It might seem like a good idea at the time, but chances are it will bite your ass later on ;)

larsm
Ahh.. that makes sense. It doesn't answer my question, but it's a very helpful explanation. +1
Mark
+1 for the vtable explaination.
RichieHindle
A: 

I propose this solution:

#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);
}

This way m_var only gets initialized once, and I keep all the construction code inside the class.

Mark
+3  A: 

I adopted this solution from the solution by Martin V Lowis. The main differences are that it uses multiple inheritance, and the 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;

Each concrete subclass of StaticInitializer gets it's own static constructor initialisation method, but you keep the advantage of having true inheritance.

1800 INFORMATION
Ah! Now that's better. It's unfortunate that you have to inherit from StaticInitializer in the derived class, but I suppose that's the best we can do. Very cool! Thanks
Mark
how do you actually compile this code/
lalitm