By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,411 Members | 1,022 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,411 IT Pros & Developers. It's quick & easy.

static class initialization functions in c++?

P: n/a
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
Dec 25 '06 #1
Share this Question
Share on Google+
8 Replies


P: n/a

"Per Bull Holmen" <pb******@yahoo.comwrote in message
news:1h******************************@yahoo.com...
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.
In C++, only a object can be initialized. A class is not an object.
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.
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.
>It is a
static member function,
In C++, only one member function of a class can initialize that
class's data members: the constructor.
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...
A constructor can not be overridden. Creation of an object of a derived
type will automatically cause its base class' constructor to be invoked.
I have been looking, but not found an equivalent in c++. Is there one?
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
Dec 25 '06 #2

P: n/a
Mike Wahler <mk******@mkwahler.netwrote:

If you tell us more specifically what you're trying to do,
perhaps we can offer more specific advice.
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
Which C++ book(s) are you reading?
"Core C++ A Software Engineering Approach" by Victor Shtern.

Per
Dec 25 '06 #3

P: n/a
Mike Wahler <mk******@mkwahler.netwrote:

If you tell us more specifically what you're trying to do,
perhaps we can offer more specific advice.
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
Which C++ book(s) are you reading?
"Core C++ A Software Engineering Approach" by Victor Shtern.

Per
Dec 25 '06 #4

P: n/a
Per Bull Holmen wrote:
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
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

Dec 25 '06 #5

P: n/a
terminator <fa***********@gmail.comwrote:
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
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
Dec 25 '06 #6

P: n/a
Per Bull Holmen wrote:
Mike Wahler <mk******@mkwahler.netwrote:

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

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.
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::ostream&
operator<<(std::ostream&, 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::ostream& operator<<(std::ostream& 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 !!

Dec 25 '06 #7

P: n/a
Per Bull Holmen wrote:
terminator <fa***********@gmail.comwrote:
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

Thanks.

I couldn't get the above code to work, I got a compile-time error.
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 .
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
you are paying an unnecessary runtime overhead for checking
"classInitialized" for every instance of myclass.

Dec 26 '06 #8

P: n/a
terminator <fa***********@gmail.comwrote:
you are paying an unnecessary runtime overhead for checking
"classInitialized" for every instance of myclass.
I know. Not bad for a complete c++ newbie, though?? :)

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

Per
Dec 26 '06 #9

This discussion thread is closed

Replies have been disabled for this discussion.