Deriving a regular class from a template?

S

Steven T. Hatton

This may be another question having an obvious answer, but I'm not seeing
it. I'm trying to create a class that derives from
std::valarray<std::string>. I don't need a template, and I haven't come
across any examples of a construct like what I show below. Perhapes it's
simply a bad idea. If there is something fundamentally wrong with this
approach please let me know.

Can anybody tell me if there is a way to get the following to work? I can
get the class StringArray to compile, but it fails to link correctly:

#include <valarray>
#include <string>

namespace stringer{
using std::valarray;
using std::string;

class StringArray:public valarray<string> {
public:
StringArray(const size_t& vsize):valarray<string>(vsize){}
};

StringArray stringV(3); // this is what seems to be failing
}

This is the point where it fails:

g++ -o stringer main.o -L/usr/lib/ -L/usr/lib/qt3/lib/ -L/usr/X11R6/lib/
-lqt -lXext -lX11 -lm
main.o(.text+0xd7): In function `__static_initialization_and_destruction_
(int, int)':
: undefined reference to `std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::_Rep::_S_empty_rep_storage'
main.o(.text+0x155): In function `__static_initialization_and_destruction_
(int, int)':
: undefined reference to `std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::_Rep::_S_empty_rep_storage'
main.o(.text+0x196): In function `__static_initialization_and_destruction_
(int, int)':
: undefined reference to `__gnu_cxx::__exchange_and_add(int volatile*, int)'
 
J

John Harrison

Steven T. Hatton said:
This may be another question having an obvious answer, but I'm not seeing
it. I'm trying to create a class that derives from
std::valarray<std::string>. I don't need a template, and I haven't come
across any examples of a construct like what I show below. Perhapes it's
simply a bad idea. If there is something fundamentally wrong with this
approach please let me know.

Can anybody tell me if there is a way to get the following to work? I can
get the class StringArray to compile, but it fails to link correctly:

#include <valarray>
#include <string>

namespace stringer{
using std::valarray;
using std::string;

class StringArray:public valarray<string> {
public:
StringArray(const size_t& vsize):valarray<string>(vsize){}
};

StringArray stringV(3); // this is what seems to be failing
}

This is the point where it fails:

g++ -o stringer
main.o -L/usr/lib/ -L/usr/lib/qt3/lib/ -L/usr/X11R6/lib/
-lqt -lXext -lX11 -lm
main.o(.text+0xd7): In function `__static_initialization_and_destruction_
(int, int)':
: undefined reference to `std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::_Rep::_S_empty_rep_storage'
main.o(.text+0x155): In function `__static_initialization_and_destruction_
(int, int)':
: undefined reference to `std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::_Rep::_S_empty_rep_storage'
main.o(.text+0x196): In function `__static_initialization_and_destruction_
(int, int)':
: undefined reference to `__gnu_cxx::__exchange_and_add(int volatile*, int)'

Your code compiles and links for me. I can't see anything illegal about it.

OTOH I'm not sure its a good idea.

Firstly from the code you posted

typedef std::valarray<std::string> StringArray;

seems a simpler option, but maybe you have reasons for doing this that
aren't in the posted code.

Secondly valarray is really designed for numeric types, I don't think using
it with strings is illegal but its a bit odd, why not
std::vector<std::string>?

Thirdly deriving from standard container classes is frowned upon because
they lack a virtual destructor. Something like this is safer and may be
closer to your needs

class StringArray
{
public:
...
private:
std::valarray<std::string> data;
};

john
 
S

Steven T. Hatton

John said:
Your code compiles and links for me. I can't see anything illegal about
it.

Indeed. I just built and installed gcc (GCC) 3.4.0. I had been using qmake
to create the Makefile. That's would have worked if my setup were
standard. But it was trying to link against a different set of libs. In
particular the -L/usr/lib. I thought gcc would take precedence over that,
until I looked it up. Oh, and then there's the aclocal-1.8 that came with
automake, and didn't get the proper symlink from the `make install'! It
goes on and on... :-/
OTOH I'm not sure its a good idea.

Firstly from the code you posted

typedef std::valarray<std::string> StringArray;

seems a simpler option, but maybe you have reasons for doing this that
aren't in the posted code.

My initial motivation was to set the values of the valarray in an
initialization function, hence the desire for a derived class.
Secondly valarray is really designed for numeric types, I don't think
using it with strings is illegal but its a bit odd, why not
std::vector<std::string>?

I'm using the strings so I can mark the individual elements while I play
around with different slicing, indexing and etc. It's just a learning toy.
Thirdly deriving from standard container classes is frowned upon because
they lack a virtual destructor.

That's good to know. I'm now wondering if I can explicitly call the
destructor on the baseclass. Hmmmm....
Something like this is safer and may be
closer to your needs

class StringArray
{
public:
...
private:
std::valarray<std::string> data;
};

That crossed my mind. In this case, it's probably better to do the has-a
rather than an is-a. Thanks for the help. The verification that it
compiled was valuable information.
 
D

Dave Moore

Steven T. Hatton said:
This may be another question having an obvious answer, but I'm not seeing
it. I'm trying to create a class that derives from
std::valarray<std::string>. I don't need a template, and I haven't come
across any examples of a construct like what I show below. Perhapes it's
simply a bad idea. If there is something fundamentally wrong with this
approach please let me know.

Can anybody tell me if there is a way to get the following to work? I can
get the class StringArray to compile, but it fails to link correctly:

#include <valarray>
#include <string>

namespace stringer{
using std::valarray;
using std::string;

class StringArray:public valarray<string> {
public:
StringArray(const size_t& vsize):valarray<string>(vsize){}
};

StringArray stringV(3); // this is what seems to be failing
}

This is the point where it fails:

g++ -o stringer main.o -L/usr/lib/ -L/usr/lib/qt3/lib/ -L/usr/X11R6/lib/
-lqt -lXext -lX11 -lm
main.o(.text+0xd7): In function `__static_initialization_and_destruction_
(int, int)':
: undefined reference to `std::basic_string<char, std::char_traits<char>,
: undefined reference to `__gnu_cxx::__exchange_and_add(int volatile*, int> std::allocator<char> >::_Rep::_S_empty_rep_storage'
main.o(.text+0x155): In function `__static_initialization_and_destruction_
(int, int)':
: undefined reference to `std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::_Rep::_S_empty_rep_storage'
main.o(.text+0x196): In function `__static_initialization_and_destruction_
(int, int)':)'

One possibility is that, since the std::valarray container is really
for optimized numerical calculations, it has some special restrictions
which cause problems if you try to initialize a valarray with a
non-numerical type (c.f. sec 26.3 of the standard). I would suggest
using std::vector<std::string> .. that should definitely work .. I
have used it myself in the past.

HTH, Dave Moore
 
M

Michiel Salters

Steven T. Hatton said:
Can anybody tell me if there is a way to get the following to work? I can
get the class StringArray to compile, but it fails to link correctly:

#include <valarray>
#include <string>

namespace stringer{
using std::valarray;
using std::string;

class StringArray:public valarray<string> {
public:
StringArray(const size_t& vsize):valarray<string>(vsize){}
};

StringArray stringV(3); // this is what seems to be failing
}

Should work, and in fact works when compiled with VC7.1. It seems
you should ask in the group for your compiler.

Regards,
Michiel Salters
 
U

Uwe Schnitker

Steven T. Hatton said:
This may be another question having an obvious answer, but I'm not seeing
it. I'm trying to create a class that derives from
std::valarray<std::string>.

This is a bad idea, for at least three reasons:

i) valarray is a special container designed for numerical applications,
so there is propbably no point in using it with string

ii) IIRC there are some restrictions in the standard for using valarray,
to the consequence that using it with string yields undefined
behaviour

iii) deriving from classes which are not designed as base classes, like
the standard library containers, is considered bad practice in C++,
e.g. the lack of a virtual destructor may prove fatal

To your more general question if one can derive a concrete class from
a template instantiation: Yes, that's possible.

If you had used vector instead of valarray, your example would be correct,
even if bad style, for reason iii).

And if you look at your error message, you might see that the code as written
compiled fine. The error message refers to a linker error. You are probable
not linking against the C++ runtime library, or maybe you are linking against
a wrong one.

To solve this problem, check your documentation or ask in a newsgroup topical
to your compiler system.
 
J

John Harrison

That's good to know. I'm now wondering if I can explicitly call the
destructor on the baseclass. Hmmmm....

There's no need to do that. The problem is with code like the following

valarray<string>* p = new StringArray(10);
delete p;

That is undefined behaviour. Deleting a derived class object through a
pointer to a base class when that base class lacks a virtual destructor
results in undefined behaviour. The issue for you is how likely it is that
code like the above will be written with your StringArray class.

john
 
D

Dave Moore

iii) deriving from classes which are not designed as base classes, like
the standard library containers, is considered bad practice in C++,
e.g. the lack of a virtual destructor may prove fatal

This idea is new to me .. do you have a reference where I can read
about it in more detail? In the past I have routinely derived classes
from std::vector and std::valarray, usually publicly, but sometimes
privately. I have done this when it seemed natural to do so in terms
of the "is-a" formalism for building class hierarchies. For example,

class positionArray : public std::vector<double> {
// some private data that is needed for manipulating the elements
// of the array
public:
positionArray(int size) : std::vector<double>(size) {
// whatever
}

void permute(); //
};


In my application positionArray is conceptually a vector of double, so
it makes sense to apply operations like subscripting directly, rather
than through an access function referencing a std::vector<double>
member. The positionArray class then would then typically also have a
few member functions for carrying out particular operations on the
underlying std::vector<double>.

I rarely use virtual functions or multiple inheritance, so the lack of
a virtual destructor has never been a problem for me .. although I
certainly see your point about that being a potential problem in the
more general case. Are there other weaknesses associated with
deriving from STL containers? If there are none, then it seems like
your advice above is perhaps a bit too restrictive.

Just my $0.02 ... Dave Moore
 
V

Victor Bazarov

Dave Moore said:
(e-mail address removed) (Uwe Schnitker) wrote in message
iii) deriving from classes which are not designed as base classes, like
the standard library containers, is considered bad practice in C++,
e.g. the lack of a virtual destructor may prove fatal
[...] Are there other weaknesses associated with
deriving from STL containers? If there are none, then it seems like
your advice above is perhaps a bit too restrictive.

No other weaknesses. The advice is usually directed at newbies so
that they don't get into a habit of deriving whenever they need to.

A note: I often find it helpful to derive privately. Then I can
control what functionality is exposed and I definitely prevent such
blunders as accidental polymorphic deletion.

Victor
 
J

Julie

Victor said:
Dave Moore said:
(e-mail address removed) (Uwe Schnitker) wrote in message
iii) deriving from classes which are not designed as base classes, like
the standard library containers, is considered bad practice in C++,
e.g. the lack of a virtual destructor may prove fatal
[...] Are there other weaknesses associated with
deriving from STL containers? If there are none, then it seems like
your advice above is perhaps a bit too restrictive.

No other weaknesses. The advice is usually directed at newbies so
that they don't get into a habit of deriving whenever they need to.

A note: I often find it helpful to derive privately. Then I can
control what functionality is exposed and I definitely prevent such
blunders as accidental polymorphic deletion.

Victor

So, if that is the case, then deriving from std containers should *NOT* be
labeled as a bad practice (bad design, etc.), but rather as an 'advanced
construct or idiom'.

I'm sure that _misnaming_ something 'bad practice/design' causes a lot more
problems that it is intended to solve.
 
C

Claudio Puviani

Julie said:
So, if that is the case, then deriving from std containers should *NOT* be
labeled as a bad practice (bad design, etc.), but rather as an 'advanced
construct or idiom'.

There's nothing advanced about the technique. It's simply error-prone, and so
should be avoided by anyone who doesn't understand the pitfalls and
limitations.
I'm sure that _misnaming_ something 'bad practice/design' causes a lot more
problems that it is intended to solve.

It is a bad practice. The mitigating factor is that an expert will be able to
make bad practices work and will know how to limit the scope. Obviously, anyone
who has worked with a tool for a substantial amount of time will know how to
use otherwise inappropriate shortcuts to good effect, but that's an attribute
of the practitioner, not of the technique. I would certainly be more confident
of something unorthodox from Victor than I would from a completely orthodox
implementation from newbie-come-lately. That doesn't change that the practice
is frowned upon in a larger context. It's not because Evel Knievel can
successfully and reproducibly jump a motorcycle over a row of buses that
suddenly it becomes an acceptable practice for all bikers. It's an acceptable
practice for Evel Knievel.

Claudio Puviani
 
P

Pete Becker

Claudio said:
There's nothing advanced about the technique. It's simply error-prone, and so
should be avoided by anyone who doesn't understand the pitfalls and
limitations.

The "pitfalls" are:

1. the behavior is undefined if you delete an object of a derived type
through a pointer to the base type.

The "limitations" are:

1. don't do that.

Of course, if you don't read documentation or don't design your code
before you write it you may well run afoul of these "pitfalls and
limitations". Too bad. Programming is a profession. If you can't pay
enough attention to do it right, don't do it at all.
 
C

Claudio Puviani

Pete Becker said:
The "pitfalls" are:

1. the behavior is undefined if you delete an object of a derived type
through a pointer to the base type.

I wasn't aware that a pointer to the base class could point to a class that
privately inherits from the base.
The "limitations" are:

1. don't do that.

Of course, if you don't read documentation or don't design your code
before you write it you may well run afoul of these "pitfalls and
limitations". Too bad.

You'll notice in the rest of my post -- which you snipped -- that I refer to
the technique as a short-cut, not as a design choice. The whole point, which I
don't believe was at all obscure, was that as a rule, it's a bad practice. In
fact, I don't hint at it; I explicitly say, "It is a bad practice."
Programming is a profession. If you can't pay enough attention
to do it right, don't do it at all.

I certainly hope this last part wasn't directed at me. You've been on this
newsgroup long enough that you've seen me bash many times the idea of
inheriting from classes that aren't designed for it. If I can homorously parody
the lecturing tone of the two last sentences: people who jump the gun shouldn't
own guns.

Claudio Puviani
 
P

Pete Becker

Claudio said:
You'll notice in the rest of my post -- which you snipped -- that I refer to
the technique as a short-cut, not as a design choice.

Sorry, I didn't mean to be as harsh as that sounded.
The whole point, which I
don't believe was at all obscure, was that as a rule, it's a bad practice. In
fact, I don't hint at it; I explicitly say, "It is a bad practice."

Yup, and I explicitly disagreed with that.
 
C

Claudio Puviani

Pete Becker said:
Sorry, I didn't mean to be as harsh as that sounded.

No problem. I'm hardly a diplomat myself. :)
Yup, and I explicitly disagreed with that.

I'm confused now. When you said, "1. don't do that," I was under the impression
that you were agreeing with me. Are you saying that inheriting from inheriting
from standard containers is a good practice? If you are -- and we'd definitely
be in disagreement -- what did you mean by "don't do that"?

Claudio Puviani
 
P

Pete Becker

Claudio said:
I'm confused now. When you said, "1. don't do that," I was under the impression
that you were agreeing with me. Are you saying that inheriting from inheriting
from standard containers is a good practice? If you are -- and we'd definitely
be in disagreement -- what did you mean by "don't do that"?

I mean what I said:
The "pitfalls" are:

1. the behavior is undefined IF YOU DELETE AN OBJECT OF A DERIVED TYPE
THROUGH A POINTER TO THE BASE TYPE.

The "limitations" are:

1. don't do that.

There are no nasty surprises here, certainly nothing to justify your
comparison to Evel Knievel.
 
C

Claudio Puviani

Pete Becker said:
I mean what I said:

Unfortunately, using pronouns tends to be ambiguous. The "that" in "don't do
that" could just as easily refered to inheriting from a non-polymorphic type. I
follow what you were saying now that "that" is bound to the preceding
statement. :)
There are no nasty surprises here, certainly nothing to justify your
comparison to Evel Knievel.

With private inheritance, I agree (and the "deleting through a pointer to the
base" admonition is also unnecessary since it can't be done). I wholeheartedly
stand by my comparison with respect to public inheritance from a
non-polymorphic type, however.

Claudio Puviani
 
P

Pete Becker

Claudio said:
With private inheritance, I agree (and the "deleting through a pointer to the
base" admonition is also unnecessary since it can't be done).

It can be done. Think a little harder.
I wholeheartedly
stand by my comparison with respect to public inheritance from a
non-polymorphic type, however.

You need to cite facts; restating your opinion doesn't add any
information. What nasty surprises do you think are here that make this
too hazardous for most programmers to use?
 
C

Claudio Puviani

Pete Becker said:
You need to cite facts; restating your opinion doesn't add any
information. What nasty surprises do you think are here that make this
too hazardous for most programmers to use?

I built up an argument, only to convince myself that you're right. Oh, there
were pitfalls all right (ex: changing the behavior in a non-virtual function
override), but they all also apply to inheritance from polymorphic types, so
it's inconsistent of me to single out non-polymorphic types for practices that
would be just as problematic elsewhere. In retrospect, those people I've seen
who had mangled projects by incorrectly inheriting from non-polymorphic types
weren't doing much better with the polymorphic types. In fact, they were doing
worse.

So consider my opinion retracted and my paranoia focused to a finer
grainularity.

Claudio Puviani
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top