Skip to main content
gamedev.net
🔒 Locked

Multiple Constructors

Started by SpaceDude 37 replies 2.4k views
Original Post
SpaceDude
SpaceDude
I have noticed something when using multiple constructors... look at this for example:
class A
{
    A(void)
    {
         m_pPointer = NULL;
         m_iVariable = 0;
    }
    A(int iSomeVariable)
    {
         A();
         m_iVariable = iSomeVariable;
    }

    object* m_pPointer;
    int m_iVariable
}
 
The second constructor there won''t work as I expected. When I put a break point in it, it calls the function A() fine... As i step through that function it sets m_pPointer to NULL, but after it returns back to the constructor m_pPointer is no longer set to NULL. I''m using MSVC++ .NET, can somebody tell me why this doesn''t work please?
Zipster
Zipster
Whenever you call a constructor manually, it actually creates a new instance of the object. So it''s initializing your variables for an anonymous temporary object.
JohnBolton
JohnBolton
Constructors are special functions that aren''t called like other functions. In your example "A()" does call the constructor, but not like it appears. It creates a temporary variable of type A and then calls the constructor on the temporary variable.

The following lines are exactly the same in the context of your code:
         A();   // <-- your version
A; // <-- this looks weird but it is perfectly legal
A x; // <-- now the variable has a name, but since it is never used...
A x(); // <-- less common
Basically, if you want several constructors to execute the same code, you have to put the code in a separate (non-constructor) function.


John Bolton
Page 44 Studios
Current project: NHL Faceoff 2005 PS2
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
SiCrane
SiCrane
quote:
Original post by JohnBolton
A x(); // <-- less common

Actually that does something different. It declares a function x that takes no arguments and returns an A object. (Still not what the original poster wanted, but something that bites people in the rear often enough in other contexts.)

Peter Diplaros
Peter Diplaros
Or even better:

class A
{
A(int v = 0) : m_pointer(NULL), m_iVariable(v) {}

object* m_pPointer;
int m_iVariable
}

where there is only one constructor with a default
argument and you''re using initializer lists, which
means it''s simpler, shorter, will most likely be inlined,
no chance of constructing temporaries, and infinately
faster.

It''s also the recommended way to do this for a class such
as yours.
JohnBolton
JohnBolton
quote:
Original post by SiCrane
quote:
Original post by JohnBolton
A x(); // <-- less common

Actually that does something different. It declares a function x that takes no arguments and returns an A object. (Still not what the original poster wanted, but something that bites people in the rear often enough in other contexts.)




Oops. (sound of being bitten in the rear) Ouch! Ha ha. I was thinking of "A x = A();"



John Bolton
Page 44 Studios
Current project: NHL Faceoff 2005 PS2
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Programmer One
Programmer One
If you want to cut down on the code, create a private member function that initilizes the variables, and call that (with different params) in the constructors.

Ex):


class ILikePie
{
public:
ILikePie (void) { Pie (0, 0, 0); }
ILikePie (int somuch) { Pie(somuch, 1337, 3.14); }
private:
void Pie (int a, double b, double c);
};
yaroslavd
yaroslavd
quote:
Original post by SpaceDude
I have noticed something when using multiple constructors... look at this for example:


class A
{
A(void)
{
m_pPointer = NULL;
m_iVariable = 0;
}
A(int iSomeVariable)
{
A();
m_iVariable = iSomeVariable;
}

object* m_pPointer;
int m_iVariable
}


The second constructor there won''t work as I expected. When I put a break point in it, it calls the function A() fine... As i step through that function it sets m_pPointer to NULL, but after it returns back to the constructor m_pPointer is no longer set to NULL. I''m using MSVC++ .NET, can somebody tell me why this doesn''t work please?


I prefer this:


class A
{
A(void)
{
this(0);
}
A(int iSomeVariable)
{
m_pPointer = NULL;
m_iVariable = iSomeVariable;
}

object* m_pPointer;
int m_iVariable
}


Simply use this(...) to call the other constructors.
Chris Hare
Chris Hare
Noooooooooooo! (in java?)


blah blah blah.
Desert Fox
Desert Fox
yaroslavd, what you have will not work in C++, you cannot under any circumstances call another constructor of an object being constructed. *this(x) will only work if you have overloaded the () operator.
The correct method is to duplicate the code of the default constructor in all of the other constructors. I recommend you do not use the "initialization function" method, even if it is private.
"Is life so dear, or peace so sweet, as to be purchased at the price of chains and slavery?" - Patrick Henry
Chris Hare
Chris Hare
quote:
Original post by Desert Fox
yaroslavd, what you have will not work in C++, you cannot under any circumstances call another constructor of an object being constructed. *this(x) will only work if you have overloaded the () operator.
The correct method is to duplicate the code of the default constructor in all of the other constructors. I recommend you do not use the "initialization function" method, even if it is private.


Why not? (with regards to a private initialisation function)


blah blah blah.
Desert Fox
Desert Fox
quote:
There may be something you can do with initialisation lists...


Nope; calling a constructor from another constructor is impossible, it cannot be done under any circumstance. (Ok, you could probably write some inline assembly to do it for you, but that''s not exactly safe)

Chris Hare:

I generally consider it bad form. The members of a class should always be initialized in an initializer list, not in the constructor body. Hence, a call to a private initialization function could override what you have in an initializer list. I like to see all of my construction code in a proper constructor.
"Is life so dear, or peace so sweet, as to be purchased at the price of chains and slavery?" - Patrick Henry
SiCrane
SiCrane
quote:
Original post by Chris Hare
Why not? (with regards to a private initialisation function)


There are several arguments against. Some are better than others.

Probably the best argument against is that if you''re using an initialization function that means you aren''t using a member initializer list, which means, in many cases, "double construction" costs.

Another problem (more common in larger projects involving multiple people) is that initializer functions often get drafted into use as more generic setters under maintence and may get a transformation applied that may use invariants that are not true at time of construction.

I''ve heard several arguments against that involve virtual function weirdness at construct time, but I don''t find them compelling enough to repeat.

Personally, I find that, usually, if a helper initialization function is necessary then I probably have a problem with my class design.
Desert Fox
Desert Fox
SiCrane and I said the same thing, he said it better though =)
"Is life so dear, or peace so sweet, as to be purchased at the price of chains and slavery?" - Patrick Henry
Chris Hare
Chris Hare
quote:
Original post by SiCrane
Probably the best argument against is that if you''re using an initialization function that means you aren''t using a member initializer list, which means, in many cases, "double construction" costs.



Would the OP''s builtins be one of these cases? I wouldn''t think so, but it''s one area I''m a bit blurry in, builtin construction.


blah blah blah.
Zahlman
Zahlman
Thanks everyone for reminding me of everything I hate about Java constructors: They only sorta-fixed one problem with C++ constructors (by creating this()/super()) and removed initializer lists in return.

Actually, in my ideal language initializer lists would be *implicit* - if you want the constructor to use an exact value of an input parameter for one of the members, then just give the formal parameter (I think I have the right term? I mean the label associated with the parameter when you write the actual function, as opposed to calling or declaring it.) the same name as the member. Anything more complicated probably should be initialized in the function body IMO though. (My general observation is that Algol-family languages make you type too much redundant stuff like this.)
SiCrane
SiCrane
quote:
Original post by Chris Hare
Would the OP''s builtins be one of these cases? I wouldn''t think so, but it''s one area I''m a bit blurry in, builtin construction.


In the OP''s case there wouldn''t be the "double construction" cost for using an initializer function vs. member initializer list. (Assuming a reasonable pre-processor environment anyway).

However, things are so simple in this case that a initialization function isn''t even close to necessary. In fact, if it had worked, there would have been the double assignment to the int variable. (Easily optimized away, but for a more complex type it might have been a different story.) I can''t think of any good reasons why a single constructor with a default argument shouldn''t be used instead of the pair of constructors. i.e.:

class A {
public:
A(int iSomeVariable = 0)
: m_pPointer(0),
m_iVariable(iSomeVariable) {}

private:
object * m_pPointer;
int m_iVariable;
};
SiCrane
SiCrane
quote:
Original post by Zahlman
Actually, in my ideal language initializer lists would be *implicit* - if you want the constructor to use an exact value of an input parameter for one of the members, then just give the formal parameter (I think I have the right term? I mean the label associated with the parameter when you write the actual function, as opposed to calling or declaring it.) the same name as the member.

IIRC, they experimented with that in one of the earlier C++ (pre-standard) implementations. (Obviously) this created more problems than it solved. If memory serves, one of the problems was that it was difficult to teach, and C++ is enough of a mess that the minor syntactic advantage wasn''t judged worth it.
SpaceDude
SpaceDude
Thanks for the replies, i see now why it doesn''t work.

quote:
Original post by SiCrane
I can''t think of any good reasons why a single constructor with a default argument shouldn''t be used instead of the pair of constructors. i.e.:

class A {
public:
A(int iSomeVariable = 0)
: m_pPointer(0),
m_iVariable(iSomeVariable) {}

private:
object * m_pPointer;
int m_iVariable;
};



I was just trying to illustrate my point with a simple example, but if you have something like this:


class A
{
public:
A();
A(object blah);
etc...
}

you can''t just use one constructor like this:

A (object blah = 0);

since blah might be some complicated object that you want initialised in a certain way.
SiCrane
SiCrane
You may not be able to use = 0, but you may be able to do something like:

class A {
public:
A(object blah = object( /* whatever */ ));
}

(Inserting consts and &''s if necessary).

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.