Topic: Reusable Constructors


Author: nr@system.ptv.de (Norbert Riedlin)
Date: 1997/10/21
Raw View
Hi there,

I know I can't do a thing like that:

class X {
public:
 X(int x, int y) : _x(x), _y(y)
 {};
 X() : this(5, 7)        // <-- 'this' not allowed here
 {};
private:
 int _x;
 int _y;
};

I think 'this' is not allowed in the marked line, because it hasn't
been constructed yet, but really I just _want_ to construct it!

I know I could have used default parameters here, but that would have
the side effect to create a third constructor with only one parameter.
I also could just copy the first constructor's initializer-list, but
nonono I just don't want to do that (Imagine a much more complex
initializer-list)

Is there no way to call a constructor for 'this' in the
initializer-list?

TIA,
Norbert
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/21
Raw View
Norbert Riedlin wrote:

> I know I can't do a thing like that:
>
> class X {
> public:
>         X(int x, int y) : _x(x), _y(y)
>         {};
>         X() : this(5, 7)        // <-- 'this' not allowed here

this doesn't make sens.

Write:
         X() : X(5, 7)  // X::X (int, int) can't be called here

>         {};
> private:
>         int _x;
>         int _y;

Avoid leading underscores.

> };
>
> I think 'this' is not allowed in the marked line, because it hasn't
> been constructed yet, but really I just _want_ to construct it!

this (something) is only allowed if you overload the () operator.

You usually never call an object:

Point p (4, 6);

p (something); // doesn't make sens

> I know I could have used default parameters here, but that would have
> the side effect to create a third constructor with only one parameter.

Right

> I also could just copy the first constructor's initializer-list, but
> nonono I just don't want to do that (Imagine a much more complex
> initializer-list)
>
> Is there no way to call a constructor for 'this' in the
> initializer-list?

Just use a private init member function:

void    X::init (int x, int y)
{
    _x = x;
    _y = y;
}

X::X () { init (5, 7); }
X::X (int x, int y) { init (x, y); }

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Gerard Weatherby <gerardw@alum.mit.edu>
Date: 1997/10/22
Raw View
Norbert Riedlin wrote:

> I know I can't do a thing like that:
>
> class X {
> public:
>         X(int x, int y) : _x(x), _y(y)
>         {};
>         X() : this(5, 7)        // <-- 'this' not allowed here
>         {};
> private:
>         int _x;
>         int _y;
> };
<snip>
> Is there no way to call a constructor for 'this' in the
> initializer-list?

Not that I've ever heard of, but you can get a similar effect with
a base class:

class Y {
protected:
        Y(int x, int y) : _x(x), _y(y)
        {};
        int _x;
        int _y;
};

class X : private Y {
public:
        X(int x, int y): Y(x,y)
        {};
        X() : Y(5, 7)        // <-- 'Y' allowed here
        {};
};
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/10/22
Raw View
nr@system.ptv.de (Norbert Riedlin) asked:
> class X
> {
> public:
>     X(int x, int y) : _x(x), _y(y) { }
>     X() : this(5, 7) { }      // <-- 'this' not allowed here
> private:
>     int  _x;
>     int  _y;
> };
>
> I think 'this' is not allowed in the marked line, because it hasn't
> been constructed yet, but really I just _want_ to construct it!
> ...
> Is there no way to call a constructor for 'this' in the
> initializer-list?

Unfortunately, no.  But by making a simple change in the draft standard,
the following constructor declaration for class X would be legal:

    X(): X(5, 7) { }    // Call X(int,int) to init members

I quote from the draft, marking the phrase in brackets that could be
changed to make this sort of thing legal:

    12.6.2  Initializing bases and members

    In the definition of a constructor for a class, initializers for
    <<direct and virtual base subobjects>> and nonstatic data members can
    be specified by a 'ctor-initializer', which has the form:

    ...

    Names in a 'mem-initializer-id' are looked up in the scope of the
    constructor's class and, if not found in that scope, are looked up
    in the scope containing the constructor's definition.  Unless the
    'mem-initializer-id' names a nonstatic data member of the constructor's
    class or a <<direct or virtual base of that class>>, the
    'mem-initializer' is ill-formed.  A 'mem-initializer-list' can
    initialize a base class using any name that denotes that base class
    type.

    ...

If we rewrote the clause in brackets to mean "the constructor's class or
a direct or virtual base class of the constructor's class", then it would
be legal to give the class name itself as a member initializer, which
would invoke one of the other class constructors.  We would have to add a
restriction that a constructor's mem-initializer-list could not name
itself as one of the mem-initializers (i.e., it must specify a constructor
with a different signature), or else we'd allow infinite looping during
object construction.

Since this change is unlikely to be made to the draft, you probably should
call a common initialization function from both constructors to avoid
duplicating code:

    class X
    {
    public:
        X(int x, int y) { init(x, y); }     // Call a common func
        X()             { init(5, 7); }     // Call a common func
    private:
        int   _x;
        int   _y;
        void  init(int x, int y);           // Common func, see below
    };

    void X::init(int x, int y)
    {
        // This func is called by all constructors of X
        // to initialize the members of X
        _x = x;
        _y = y;
    }

This is not exactly what you had in mind, but it comes close.  Be careful,
though, since the object is not fully constructed when X::init() is called.
The initialization function should do little more than initializing the
member variables of the object.

-- David R. Tribble, david.tribble@beasys.com --
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/10/22
Raw View
Valentin Bonnard wrote:
>
> Norbert Riedlin wrote:
>
> > I also could just copy the first constructor's initializer-list, but
> > nonono I just don't want to do that (Imagine a much more complex
> > initializer-list)
> >
> > Is there no way to call a constructor for 'this' in the
> > initializer-list?
>
> Just use a private init member function:
>
> void    X::init (int x, int y)
> {
>     _x = x;
>     _y = y;
> }
>
> X::X () { init (5, 7); }
> X::X (int x, int y) { init (x, y); }

While this is the common solution, it doesn't cover all cases.
How would you f.ex. do it with the following?

class MyClass
{
  OtherClass& other;
  int i;
  static OtherClass default_other;
public:
  MyClass(OtherClass& oc, int x, int y): other(os), i(x)
    { other.set_attr(y); }
  MyClass(): MyClass(default_other, 1, 0) {} // not allowed
};

Of course, you could change the reference to a pointer, but you
might have reasons for using a reference (to express the fact that
it references the same object during the whole lifetime). Making it
a const pointer wouldn't help either, as const member objects have
to be initialized in the initializer list as well.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]