static class initialization functions in c++?

Discussion in 'C++' started by Per Bull Holmen, Dec 25, 2006.

  1. Hey

    Im new to c++, so bear with me. I'm used to other OO languages, where it
    is possible to have class-level initialization functions, that
    initialize the CLASS rather than an instance of it. Like, for instance
    the Objective-C method:

    +(void)initialize

    Which has the following characteristics: It is guaranteed to be run
    before the first instance of that particular class is created. It is a
    static member function, which otherwise operates the same way as any
    other such functions: It can be overridden by subclasses, and the
    overridden can call the superclass' implementation if needed, etc...

    I have been looking, but not found an equivalent in c++. Is there one?

    Per
     
    Per Bull Holmen, Dec 25, 2006
    #1
    1. Advertisements

  2. Per Bull Holmen

    Mike Wahler Guest

    In C++, only a object can be initialized. A class is not an object.
    A C++ class can contain static member objects, which are initialized
    before 'main()' begins. If there is more than one static (member or
    nonmember) object in the program, the order of their initialization
    is not specified by the language.
    In C++, only one member function of a class can initialize that
    class's data members: the constructor.
    A constructor can not be overridden. Creation of an object of a derived
    type will automatically cause its base class' constructor to be invoked.
    class B
    {
    static int i;
    int j;
    public:
    B(int arg = 0) : j(arg) /* constructor */
    {
    }
    };

    int B::i = 42; /* initialize B::i with the value 42 */


    class D : public B
    {
    static int m;
    int k;
    public:
    D(int Bval, int kval) : B(Bval), k(kval) /* constructor */
    {
    }
    };

    int D::m = 10; /* initialize D::m with the value 10 */

    int main()
    {
    B b_obj(99); /* create an object of type 'B', and
    intialize it's member 'j' with the
    value 99 */

    D d_obj(25, 32); /* create an object of type 'D', initialize
    its base portion (via its constructor 'B::B()')
    with value 25, and initialize its member 'k' with
    value 32 */
    return 0;
    }

    If you tell us more specifically what you're trying to do,
    perhaps we can offer more specific advice.

    Which C++ book(s) are you reading?
    -Mike
     
    Mike Wahler, Dec 25, 2006
    #2
    1. Advertisements

  3. I'm trying to write a base class for scriptable objects. The subclasses
    of this class hold a set of properties that must be identified by name
    (a string), that can be retrieved or set by a script. But never mind the
    scripting, I just explain it so you can see why the properties must be
    identified by names. When the member functions

    int Scriptable::luaGetProperty( lua_State *lua, string &propertyName )
    int Scriptable::luaSetProperty( lua_State *lua, string &propertyName )

    are called on the scriptable objects, the respective subclasses must be
    free to implement the getting and setting of these properties
    themselves, so it's not possible to just let these properties be held by
    some hashtable. It would be nice to let the subclass just forward the
    requests to the following member functions:

    int Scriptable::luaGetProperty( lua_State *lua, int propertyCode )
    int Scriptable::luaSetProperty( lua_State *lua, int propertyCode )

    which take an int code (i.e. an enum) instead of an action name, cause
    then I can just use switch statements like this:

    switch( propertyCode ) {
    case HEIGHT_PROPERTY:
    // perform code to get/set height
    case WIDTH_PROPERTY:
    // etc...
    }

    My problem is the following: I thought it would be a bad idea to
    hardcode all property names and respective codes in the base class. So,
    I thought I'd let the base class hold a registry of property names and
    codes in a hashtable, as a static member shared by subclasses. Then, any
    subclass that adds new properties, can call the function:

    void Scriptable::registerPropertyCode( string &name, int code ) {
    properties.put( name, code );
    }

    Where properties is the hashtable. In the main other language I've been
    programming in (Objective-C), I would simply make the class initializer
    call a static member function, declared something like this:

    class Scriptable {

    /.../

    static void registerProperties();

    /.../
    };

    So that any subclass can override this to add their own properties. I
    thought the cleanest way to do this, would be to make the class
    guarantee that the properties were registered before any instances of
    the class were set into action. I might do it in the constructors,
    though, but I thought it wouldn't be optimal. I'm sure there's a
    workaround for this specific problem, but I'm trying to learn how to
    solve this type of problems in the future
    "Core C++ A Software Engineering Approach" by Victor Shtern.

    Per
     
    Per Bull Holmen, Dec 25, 2006
    #3
  4. I'm trying to write a base class for scriptable objects. The subclasses
    of this class hold a set of properties that must be identified by name
    (a string), that can be retrieved or set by a script. But never mind the
    scripting, I just explain it so you can see why the properties must be
    identified by names. When the member functions

    int Scriptable::luaGetProperty( lua_State *lua, string &propertyName )
    int Scriptable::luaSetProperty( lua_State *lua, string &propertyName )

    are called on the scriptable objects, the respective subclasses must be
    free to implement the getting and setting of these properties
    themselves, so it's not possible to just let these properties be held by
    some hashtable. It would be nice to let the base class just forward the
    requests to the following member functions:

    int Scriptable::luaGetProperty( lua_State *lua, int propertyCode )
    int Scriptable::luaSetProperty( lua_State *lua, int propertyCode )

    which take an int code (i.e. an enum) instead of an action name, cause
    then I can just use switch statements like this:

    switch( propertyCode ) {
    case HEIGHT_PROPERTY:
    // perform code to get/set height
    case WIDTH_PROPERTY:
    // etc...
    }

    My problem is the following: I thought it would be a bad idea to
    hardcode all property names and respective codes in the base class. So,
    I thought I'd let the base class hold a registry of property names and
    codes in a hashtable, as a static member shared by subclasses. Then, any
    subclass that adds new properties, can call the function:

    void Scriptable::registerPropertyCode( string &name, int code ) {
    properties.put( name, code );
    }

    Where properties is the hashtable. In the main other language I've been
    programming in (Objective-C), I would simply make the class initializer
    call a static member function, declared something like this:

    class Scriptable {

    /.../

    static void registerProperties();

    /.../
    };

    So that any subclass can override this to add their own properties. I
    thought the cleanest way to do this, would be to make the class
    guarantee that the properties were registered before any instances of
    the class were set into action. I might do it in the constructors,
    though, but I thought it wouldn't be optimal. I'm sure there's a
    workaround for this specific problem, but I'm trying to learn how to
    solve this type of problems in the future
    "Core C++ A Software Engineering Approach" by Victor Shtern.

    Per
     
    Per Bull Holmen, Dec 25, 2006
    #4
  5. Per Bull Holmen

    terminator Guest

    such a syntax does not exist in C++ but you can device the dummy
    variable initialization technique:

    class myclass{
    private:
    struct initializer{
    initializer(){
    //do write initialization code here
    };//end initializer()
    };//end struct initializer

    friend struct initializer; /*grant initializer the permission to
    axcess private members of mystruct*/

    static initializer unused; //unused variable

    }; //end class myclass

    myclass::initializer myclass::unused(); //invoke initialization
     
    terminator, Dec 25, 2006
    #5
  6. Thanks.

    I couldn't get the above code to work, I got a compile-time error. With
    my present knowledge of c++, I couldn't figure out what was wrong, but I
    tried to use the same idea slightly differently:

    class myclass {

    static bool initialized; //unused variable

    static bool initialize() {
    printf( "Init\n" );
    return( true );
    }

    public:
    myclass() {}

    }; //end class myclass

    bool myclass::initialized = myclass::initialize(); //invoke
    initialization

    This worked fine, but sometimes one might want to be guaranteed that all
    superclasses' initializers get invoked before a subclass' initializer. I
    couldn't do that without changing the constructors a bit, because the
    order of initialization of static class members is undefined, and I
    can't rely on some static bool initialized value being false if it
    hasn't been - well - initialized. With the following code it worked:

    class myclass {

    static bool classInitialized;

    static void initializeClass() {
    printf( "Init base\n" );
    classInitialized = true;
    }

    public:
    myclass() {
    if( ! classInitialized )
    initializeClass();
    }

    }; //end class myclass

    bool myclass::classInitialized = false;

    class subclass : myclass {

    static bool classInitialized;

    static void initializeClass() {
    printf( "Init sub\n" );
    classInitialized = true;
    }

    public:
    subclass() {
    if( ! classInitialized )
    initializeClass();
    }

    }; //end class myclass

    bool subclass::classInitialized = false;

    Since myclass' constructor gets implicitly invoked when a new instance
    of subclass is created, this should guarantee that all superclasses get
    initialized first. It seems that when an instance of subclass invokes
    myclass' constructor, it uses the myclass::classInitialized variable
    rather than subclass::classInitialized. Am I relying on undefined
    behaviour here, or is this part of the c++ standard?

    Per
     
    Per Bull Holmen, Dec 25, 2006
    #6
  7. Per Bull Holmen

    Salt_Peter Guest

    You want to respect the relationship between the base class and its
    subclasses.
    Not just use the base class as a universal repository of static
    properties.

    Its completely conceivable to have some static repository of properties
    in your program, but don't put it in your base class. Let a static
    collection of properties live outside of the class. That way, you can
    create different Scriptable derivatives based on different sets of
    static data.

    See if the code below helps. Note that std::map is not neccessarily a
    solution here. Its just a suggestion (std::maps load reletively slowly
    but search/find is infinitely faster that an array with op[]). You
    might also consider using a reference to a static collection in your
    base class with a set of Scriptables referring to one static map
    collection and another set of Scriptables referring to some other
    static collection. The possibilities are endless.

    Note the ctors that take an external std::map collection as a
    parameter.

    #include <iostream>
    #include <ostream>
    #include <map>

    class Base
    {
    std::map< std::string, int > properties;
    public:
    Base() : properties() { }
    Base(std::map< std::string, int >& r_m) : properties(r_m) { }
    Base(const Base& copy) { properties = copy.properties; }
    virtual ~Base() { }
    /* virtual member functions */
    virtual void /* staggered to fit */
    registerPropertiesCode(const std::string&, const int) = 0;
    virtual int
    getProperty(const std::string& r_s) const;
    /* global friend op<< */
    friend std::eek:stream&
    operator<<(std::eek:stream&, const Base&);
    };

    void
    Base::registerPropertiesCode(const std::string& r_s, const int n)
    {
    properties.insert( std::make_pair< std::string, int >(r_s, n) );
    }

    int
    Base::getProperty(const std::string& r_s) const
    {
    typedef std::map< std::string, int >::const_iterator MIter;
    MIter found = properties.find( r_s );
    if(found != properties.end())
    return (*found).second;
    else
    return -1;
    }

    std::eek:stream& operator<<(std::eek:stream& os, const Base& r_b)
    {
    typedef std::map< std::string, int >::const_iterator MIter;
    for( MIter miter = r_b.properties.begin();
    miter != r_b.properties.end();
    ++miter )
    {
    os << "property: " << (*miter).first;
    os << "\t" << "value: " << (*miter).second;
    os << "\n";
    }
    return os;
    }

    class Scriptable : public Base
    {
    public:
    Scriptable() { }
    Scriptable(std::map< std::string, int >& m) : Base(m) { }
    Scriptable(const Scriptable& copy) : Base(copy)
    {
    }
    /* required virtuals */
    void
    registerPropertiesCode(const std::string& r_s, const int n)
    {
    Base::registerPropertiesCode(r_s, n);
    }
    };

    int main()
    {
    Scriptable instance;
    instance.registerPropertiesCode("HEIGHT_PROPERTY", 60);
    instance.registerPropertiesCode("WIDTH_PROPERTY", 100);
    instance.registerPropertiesCode("XCOORD_PROPERTY", 10);
    instance.registerPropertiesCode("YCOORD_PROPERTY", 0);

    std::cout << "get WIDTH_PROPERTY: ";
    std::cout << instance.getProperty("WIDTH_PROPERTY");
    std::cout << std::endl;
    std::cout << "get BOGUS_PROPERTY: ";
    std::cout << instance.getProperty("BOGUS_PROPERTY");
    std::cout << std::endl;

    std::cout << instance << std::endl; // friend op<<

    Scriptable copy(instance); // copy the properties
    std::cout << copy << std::endl;

    static std::map< std::string, int > mycollection;
    mycollection.insert(
    std::make_pair< std::string, int >("FIRST_PROPERTY", 1) );
    mycollection.insert(
    std::make_pair< std::string, int >("SECOND_PROPERTY", 2) );
    mycollection.insert(
    std::make_pair< std::string, int >("THIRD_PROPERTY", 3) );

    Scriptable another(mycollection);
    std::cout << another << std::endl;
    }

    /*
    get WIDTH_PROPERTY: 100
    get BOGUS_PROPERTY: -1 // probably not appropriate
    property: HEIGHT_PROPERTY value: 60
    property: WIDTH_PROPERTY value: 100
    property: XCOORD_PROPERTY value: 10
    property: YCOORD_PROPERTY value: 0

    property: HEIGHT_PROPERTY value: 60
    property: WIDTH_PROPERTY value: 100
    property: XCOORD_PROPERTY value: 10
    property: YCOORD_PROPERTY value: 0

    property: FIRST_PROPERTY value: 1
    property: SECOND_PROPERTY value: 2
    property: THIRD_PROPERTY value: 3
    */

    Merry Xmas to all !!
     
    Salt_Peter, Dec 25, 2006
    #7
  8. Per Bull Holmen

    terminator Guest

    I coud not either.this seems to be my mistake in syntax.but I removed
    the braces in the last line and it compiled and worked.so change that
    line to this:

    /* outside class declaration of static member variable :constructing it
    with default (none parameterd) constructor */
    myclass::initializer myclass::unused;
    /*myclass::initializer myclass::unused(); */ /*do not uncomment:
    error on this line*/

    In C++ you must declare static member variables outside the class and
    select the constructor that initializes it.try this:



    class myclass{
    protected:
    struct initializer{
    initializer(){
    printf("initialize default\n");
    };//end initializer()

    initializer(int data){
    printf("initialize with: %d\n",data);
    };//end initializer(int)

    };//end struct initializer

    friend struct initializer; /*grant initializer the permission to
    axcess private members of mystruct*/

    private:
    static initializer svar1,svar2; //static variables

    }; //end class myclass


    myclass::initializer myclass::svar1 /* default constructor
    */
    ,myclass::svar2(13); /*parametered
    constructor*/

    struct subclass:
    public myclass //inherit publicly
    {// begin subclass

    private:

    typedef myclass::initializer InitializerBase; /*
    declare a private nested type*/

    protected:

    class initializer:
    private InitializerBase //inherit privately
    {// begin class initializer

    public:

    initializer() {printf("subclass\n");};

    initializer(char c) :
    InitializerBase(c) /*choose parametered version
    of base constructor*/
    {// begin initializer (char)

    printf("subclass with %c\n",c);

    };// end initializer (char)

    };// end class initializer

    public:

    static initializer sub1,sub2; //static stuff

    };// end subclass

    subclass::initializer subclass::sub1 /* default constructor */
    ,subclass::sub2('A');/*parametered
    constructor*/



    For the sake of implicit call to base class static constructor , have
    every derived class`s initializer type to be a subclass of that of the
    base class(in this case "struct initializer" must be not private ; so
    have it protected).You can also put some of your static member
    variables in initializer ,this increases encapsulation and "unused"
    will not be unused any more .
    you are paying an unnecessary runtime overhead for checking
    "classInitialized" for every instance of myclass.
     
    terminator, Dec 26, 2006
    #8
  9. I know. Not bad for a complete c++ newbie, though?? :)

    Thanks for your help, I'll try your code later.

    Per
     
    Per Bull Holmen, Dec 26, 2006
    #9
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.