C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

trick to access derived members in base constructor

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Paul Rosen
Guest





PostPosted: Wed Oct 26, 2005 11:15 pm    Post subject: trick to access derived members in base constructor Reply with quote



I have something like this:

[Note: This code is truncated as much as possible to illustrate the
problem.]

typedef std::vector<std::string> VStr;

class MyBase
{
public:
explicit MyBase(VStr& vstr) { /* initialize vstr */ };
};

class MyDerived
{
public:
explicit MyDerived(VStr& vstr)
: MyBase(vstr)
{};
};

Now, that all works fine. I've recently needed to create another derived
class, though, that needs the vector as a member instead. I'd like to do
this:

class MyDerived2
{
public:
MyDerived2()
: MyBase(m_vstr)
{};
private:
VStr m_vstr;
};

But, of course, m_vstr isn't initialized at the time that MyBase's ctor
is called.

I'd rather not change MyBase because it is used in a number of places
already.

What I did to get around the problem is the following ugly hack. Can
anyone suggest anything that is thread safe and prettier?

static VStr s_vstrScratch;
class MyDerived2
{
public:
MyDerived2()
: MyBase(s_vstrScratch)
, m_vstr(s_vstrScratch)
{};
private:
VStr m_vstr;
};


Thanks!

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Alf P. Steinbach
Guest





PostPosted: Thu Oct 27, 2005 10:31 am    Post subject: Re: trick to access derived members in base constructor Reply with quote



* Paul Rosen:
Quote:
I have something like this:

[Note: This code is truncated as much as possible to illustrate the
problem.]

typedef std::vector<std::string> VStr;

class MyBase
{
public:
explicit MyBase(VStr& vstr) { /* initialize vstr */ };
};

class MyDerived
{
public:
explicit MyDerived(VStr& vstr)
: MyBase(vstr)
{};
};

Now, that all works fine.

Be aware that "works" is not the same as "sound design" or "robust
against maintenance" or even "understandable".

The code you currently have in the MyBase constructor should not be
there: it has nothing to do with the construction of a MyBase object.

It should probably be a freestanding helper function.


Quote:
I've recently needed to create another derived
class, though, that needs the vector as a member instead. I'd like to do
this:

class MyDerived2
{
public:
MyDerived2()
: MyBase(m_vstr)
{};
private:
VStr m_vstr;
};

But, of course, m_vstr isn't initialized at the time that MyBase's ctor
is called.

Right, but equally true, m_vstr _is_ guaranteed initialized when
MyDerived2's constructor body is executed, and that's a good place to
call the freestanding function you should have had.

If you're not overly concerned with efficiency you can, alternatively,
make that a function that returns a VStr, and call it in MyDerived2's
constructor initializer list.

If that turns out to be magnitudes too slow, you can then change the
function's result type, and the type of m_vstr, to std::auto_ptr<VStr>
(where you discover how smart it was to only ever access that member via
a getter function, in the rest of the code), but personally I'd go for
the call in the constructor body instead.


Quote:
I'd rather not change MyBase because it is used in a number of places
already.

That's why you should change MyBase immediately, or better, excise it
from your system, torch-burn it, and give the ashes to a homeopath (so
they'll be sufficiently diluted to never again rise like Terminator II).


Quote:
What I did to get around the problem is the following ugly hack. Can
anyone suggest anything that is thread safe and prettier?

See above.

Hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Ulrich Eckhardt
Guest





PostPosted: Thu Oct 27, 2005 10:34 am    Post subject: Re: trick to access derived members in base constructor Reply with quote



Paul Rosen wrote:
Quote:
typedef std::vector<std::string> VStr;

class MyBase
{
public:
explicit MyBase(VStr& vstr) { /* initialize vstr */ };
};
[...]
static VStr s_vstrScratch;
class MyDerived2
{
public:
MyDerived2()
: MyBase(s_vstrScratch)
, m_vstr(s_vstrScratch)
{};
private:
VStr m_vstr;
};

Hmmm, if you can pass a scratch object, it seems like it is not really
needed, so I guess the whole design smells a bit fishy.
Other than that, you could use the fact that base-classes are initialized
in their order and put the vector in a baseclass. IIRC, Boost even has a
helper for that, but can't remember its name.

--
Questions ?
see C++-FAQ Lite: http://parashift.com/c++-faq-lite/ first !


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Daniel Krügler
Guest





PostPosted: Thu Oct 27, 2005 10:36 am    Post subject: Re: trick to access derived members in base constructor Reply with quote

Paul Rosen wrote:
Quote:
I have something like this:

[Note: This code is truncated as much as possible to illustrate the
problem.]

typedef std::vector<std::string> VStr;

class MyBase
{
public:
explicit MyBase(VStr& vstr) { /* initialize vstr */ };
};

class MyDerived
{
public:
explicit MyDerived(VStr& vstr)
: MyBase(vstr)
{};
};

I assume you meant:

class MyDerived : public MyBase
{
.....
};


Quote:

Now, that all works fine. I've recently needed to create another derived
class, though, that needs the vector as a member instead. I'd like to do
this:

class MyDerived2
{
public:
MyDerived2()
: MyBase(m_vstr)
{};
private:
VStr m_vstr;
};

I assume you meant:

class MyDerived2 : public MyBase
{
.....
};


Quote:
I'd rather not change MyBase because it is used in a number of places
already.

What I did to get around the problem is the following ugly hack. Can
anyone suggest anything that is thread safe and prettier?

static VStr s_vstrScratch;
class MyDerived2
{
public:
MyDerived2()
: MyBase(s_vstrScratch)
, m_vstr(s_vstrScratch)
{};
private:
VStr m_vstr;
};

This workaround not only has thread-safety problems, but also is
sensitive to the order-of-initialization problem (consider the situation
that there somewhere exists a global MyDerived2 instance...)

You can do the following:

class ArrayWrapper {
protected:
VStr m_vstr;
};

class MyDerived2 : private ArrayWrapper, public MyBase
{
public:
MyDerived2() :
ArrayWrapper(),
MyBase(m_vstr) // It is ok now to access m_vstr in the base class!
{
}

};

Boost provides a helper class template, base_from_member, which
supports this special kind of initialization problem and can even be
used for multiple member situations.

Greetings from Bremen,

Daniel Krügler

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Yuri Khan
Guest





PostPosted: Thu Oct 27, 2005 10:38 am    Post subject: Re: trick to access derived members in base constructor Reply with quote

Paul Rosen wrote:
Quote:
I have something like this:

typedef std::vector<std::string> VStr;

class MyBase
{
public:
explicit MyBase(VStr& vstr) { /* initialize vstr */ };
};

Now, that all works fine. I've recently needed to create another derived
class, though, that needs the vector as a member instead. I'd like to do
this:

class MyDerived2 : public MyBase
{
public:
MyDerived2()
: MyBase(m_vstr)
{};
private:
VStr m_vstr;
};

But, of course, m_vstr isn't initialized at the time that MyBase's ctor
is called.

As you've pointed out, the m_vstr does not yet exist when
MyBase::MyBase runs. You may store a pointer or reference for future
use, but may not access the object itself, period.

You may, however, cause the m_vstr to be constructed earlier, by moving
it to another base class and putting that earlier in the list of bases:

class MyBase3
{
protected:
VStr m_vstr;
};

class MyDerived3 : private MyBase3, public MyBase // order matters!
{
public:
MyDerived3() :
// first, MyBase3 is default-constructed,
// and as part of it, m_vstr is default-constructed.
// Then, we construct MyBase, passing it our m_vstr:
MyBase(m_vstr)
{}
};

But generally speaking, you probably have a design error here. Why
would you want to modify something passed into your constructor?


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Paul Rosen
Guest





PostPosted: Fri Oct 28, 2005 8:27 am    Post subject: Re: trick to access derived members in base constructor Reply with quote

Daniel Krügler wrote:

Quote:
Boost provides a helper class template, base_from_member, which
supports this special kind of initialization problem and can even be
used for multiple member situations.

A number of people suggested this, and thanks! The first line of the
documentation says:

"The class template boost::base_from_member provides a workaround for a
class that needs to initialize a base class with a member."

That pretty much nails the problem. Thanks all!

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.