 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Paul Rosen Guest
|
Posted: Wed Oct 26, 2005 11:15 pm Post subject: trick to access derived members in base constructor |
|
|
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
|
Posted: Thu Oct 27, 2005 10:31 am Post subject: Re: trick to access derived members in base constructor |
|
|
* 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
|
Posted: Thu Oct 27, 2005 10:34 am Post subject: Re: trick to access derived members in base constructor |
|
|
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
|
Posted: Thu Oct 27, 2005 10:36 am Post subject: Re: trick to access derived members in base constructor |
|
|
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
|
Posted: Thu Oct 27, 2005 10:38 am Post subject: Re: trick to access derived members in base constructor |
|
|
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
|
Posted: Fri Oct 28, 2005 8:27 am Post subject: Re: trick to access derived members in base constructor |
|
|
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 |
|
 |
|
|
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
|
|