STL extension

P

Park Ho-Kyung

Hello.

I try to extend STL, for example, add member function like trim_left to
basic_string<charT, traits, Alloc>. However I am in the despair as soon as I
see
STL source. I am using STLport 5.0-0409 with vc 6.0.

How can I extend STL easily? Any help will be appreciated. Thanks.
 
D

David Hilsee

Park Ho-Kyung said:
Hello.

I try to extend STL, for example, add member function like trim_left to
basic_string<charT, traits, Alloc>. However I am in the despair as soon as I
see
STL source. I am using STLport 5.0-0409 with vc 6.0.

How can I extend STL easily? Any help will be appreciated. Thanks.

If you want a trim_left function that operates on a std::string, then you
should implement it as a non-member function. The standard container
classes were not designed for inheritance. There is no reason to extend a
container class to add member functions because that provides no significant
benefits over the non-member function approach. Assuming that you wish to
remove some characters from the string, you could implement it like so:

// returns the result
std::string trim_left( const std::string& s );

// or

// modifies the argument
void trim_left( std::string& s );

You could place this function in a namespace if you don't want it to be in
the global namespace.
 
I

Ian

Park said:
Hello.

I try to extend STL, for example, add member function like trim_left to
basic_string<charT, traits, Alloc>. However I am in the despair as soon as I
see
STL source. I am using STLport 5.0-0409 with vc 6.0.

How can I extend STL easily? Any help will be appreciated. Thanks.
Derive your own classes form those in the STL and add your new
functionality. Don't mess with what's there, that's not the C++ way!

Ian
 
D

Denis Remezov

Kevin W. said:

Since the said classes have non-virtual destructors, it is immoral to
inherit from them publicly (this has been beaten to death). It may
be a convenient thing to do, but you'd better keep it low, because
a class so derived would not be safe for general-purpose use.
Also, if you tried to preserve all of the base class functionality,
you would have to redefine the constructors (they are plentiful).

There is nothing fundamentally wrong in inheriting from standard
container classes privately. However, there is no advantage in doing
so either (the protected parts, if usable, are undocumented and
library-specific; there are no virtual functions to override, etc.).
Containment would be a better option.

Other than semantically. IMO, it's a lot more logical to write
str.trim_left() than trim_left(str).

It's arguable on both sides. This and other operations can be implemented
in terms of a minimal public interface of a corresponding container class.
Some of these operations could be made generic in respect to the container
type.

Denis
 
K

Kevin W.

The standard container classes were not designed for inheritance.

How not?
There is no reason to extend a container class to add member functions
because that provides no significant benefits over the non-member
function approach.

Other than semantically. IMO, it's a lot more logical to write
str.trim_left() than trim_left(str).
 
K

Kai-Uwe Bux

Denis said:
Since the said classes have non-virtual destructors, it is immoral to
inherit from them publicly (this has been beaten to death). It may
be a convenient thing to do, but you'd better keep it low, because
a class so derived would not be safe for general-purpose use.

So then, what about inheriting from a patched string class:


#include <string>

class inheritable_string : public std::string {
public:

inheritable_string ( void ) :
std::string ()
{}

template < typename A >
inheritable_string ( A a ) :
std::string ( a )
{}

template < typename A, typename B >
inheritable_string ( A a, B b ) :
std::string ( a, b )
{}

template < typename A, typename B, typename C >
inheritable_string ( A a, B b, C c ) :
std::string ( a, b, c )
{}

template < typename A, typename B, typename C,
typename D >
inheritable_string ( A a, B b, C c, D d ) :
std::string ( a, b, c, d )
{}

template < typename A, typename B, typename C,
typename D, typename E >
inheritable_string ( A a, B b, C c, D d, E e ) :
std::string ( a, b, c, d, e )
{}

template < typename A, typename B, typename C,
typename D, typename E, typename F >
inheritable_string ( A a, B b, C c, D d, E e, F f ) :
std::string ( a, b, c, d, e, f )
{}

virtual ~inheritable_string ( void ) {}

};

Would it be safe to inherit from here.

Also, if you tried to preserve all of the base class functionality,
you would have to redefine the constructors (they are plentiful).

Is something wrong with the use of templated constructors?



Best

Kai-Uwe Bux
 
D

David Hilsee

Kai-Uwe Bux said:
So then, what about inheriting from a patched string class:


#include <string>

class inheritable_string : public std::string {
public:

inheritable_string ( void ) :
std::string ()
{}

template < typename A >
inheritable_string ( A a ) :
std::string ( a )
{}

template < typename A, typename B >
inheritable_string ( A a, B b ) :
std::string ( a, b )
{}

template < typename A, typename B, typename C >
inheritable_string ( A a, B b, C c ) :
std::string ( a, b, c )
{}

template < typename A, typename B, typename C,
typename D >
inheritable_string ( A a, B b, C c, D d ) :
std::string ( a, b, c, d )
{}

template < typename A, typename B, typename C,
typename D, typename E >
inheritable_string ( A a, B b, C c, D d, E e ) :
std::string ( a, b, c, d, e )
{}

template < typename A, typename B, typename C,
typename D, typename E, typename F >
inheritable_string ( A a, B b, C c, D d, E e, F f ) :
std::string ( a, b, c, d, e, f )
{}

virtual ~inheritable_string ( void ) {}

};

Would it be safe to inherit from here.

No, the std::string is still exposed.

std::string * p = new inheritable_string();
delete p; // this is a problem

However, the whole virtual destructor issue, to me, is secondary to the fact
that a public inheritance from std::string (or any other standard container)
is, from a design standpoint, about the same as exposing that base class as
a public member. That is, there's not a whole lot of difference between the
following two classes, aside from the need to write "foo.str" instead of
"foo" to access the std::string.

class foo : public std::string {};
class foo {
public:
std::string str; // foo has same benefits as before
};
 
J

Jeff Flinn

Park Ho-Kyung said:
Hello.

I try to extend STL, for example, add member function like trim_left to
basic_string<charT, traits, Alloc>. However I am in the despair as soon as I
see

save yourself the trouble, wait a week or two, then see the string algorithm
library at www.boost.org. The string algorithm library will be in version
1.32, or follow the directions at the website to get access to the CVS
version.

Jeff F
 
D

David Hilsee

Kevin W. said:

As Denis pointed out, it has no virtual functions (including the important
destructor) and no protected members. Derived classes get no extra
benefits.
Other than semantically. IMO, it's a lot more logical to write
str.trim_left() than trim_left(str).

Logical, or pretty? Lots of the functions in the C++ library are not member
functions (e.g. sin(), sort()), and, for the most part, they don't seem any
more or less logical than the member functions.
 
L

lilburne

Kevin said:
Other than semantically. IMO, it's a lot more logical to write
str.trim_left() than trim_left(str).

Actually it probably isn't:
http://www.cuj.com/documents/s=8042/cuj0002meyers/

"In 1998, however, I gave a presentation at Actel, where Arun Kundu
observed that my algorithm dictated that functions should be member
functions even when they could be implemented as non-members that
used only C's public interface. Is that really what I meant, he asked
me? In other words, if f could be implemented as a member function or
a non-friend non-member function, did I really advocate making it a
member function? I thought about it for a moment, and I decided that
that was not what I meant."
 
D

Default User

Park said:
Hello.

I try to extend STL, for example, add member function like trim_left to
basic_string<charT, traits, Alloc>. However I am in the despair as soon as I
see
STL source. I am using STLport 5.0-0409 with vc 6.0.

How can I extend STL easily? Any help will be appreciated. Thanks.

One approach is to make a wrapper class for your string and then add
your new functions to it.



class StringWrapper
{
public:
std::string str;
trim_left();
};


You could also make the string member private and provide an access
facade if you prefered, or just leave it public knowing that users could
manipulate it directly.



Brian Rodenborn
 
J

Jesper Madsen

If you put a trim_left member function on a string, i would expect "the
string" to be trimmed when calling trim_left(), and would not want a
std::string returned...
But when you have a free function, it operates on the parameter you give it,
and returns a result...

class MyString {
...
public:
...
void trim_left();
...
};

std::string trim_left(const std::string& s);
or
void trim_left(std::string&);

If a trim_left should be a natural function, on a class it would have to be
a "class function"/"static".. And that i would not do for a trim_left...
Syntax being something like
"std::string trimmed = std::string::trim_left( untrimmed );"

So at least for me the free function seems more intuitive... ;)

Jesper
 
K

Kevin W.

Logical, or pretty? Lots of the functions in the C++ library are not
member functions (e.g. sin(), sort()), and, for the most part, they
don't seem any more or less logical than the member functions.

sin() acts on a primitive type, so cannot be a member function. sort() is
a generic function, so likewise, cannot be a member of anything. Why are
almost all of the standard library functions that act on strings members
of the string class (this doesn't only apply to strings), and why should
we go against this convention?

Making functions members reinforces the relationship with the class and
reduces the argument count, preventing confusion as to the order of the
arguments.
 
D

David Hilsee

Kevin W. said:
sin() acts on a primitive type, so cannot be a member function. sort() is
a generic function, so likewise, cannot be a member of anything. Why are
almost all of the standard library functions that act on strings members
of the string class (this doesn't only apply to strings), and why should
we go against this convention?

The std::string class has been attacked by experts for its excessively large
number of members. It has been called a "monolith" class whose members are
more reusable and more understandable as non-members. I would not hold it
up as a model of good design. See Sutter's GOTW about std::string's members
(http://www.gotw.ca/gotw/084.htm). That sort of class design may be a
convention, but it is a convention that has been challenged by a lot of
smart people (see lilburne's reference to the Meyers article for another
example). Their arguments make a lot of sense. That is why we should go
against it.
Making functions members reinforces the relationship with the class and
reduces the argument count, preventing confusion as to the order of the
arguments.

IMHO, reducing an argument count by one doesn't improve anyhing to a
significant degree. There are other equally good ways to express
relationships, like namespaces and header/implementation file organization.
 

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
474,175
Messages
2,570,942
Members
47,489
Latest member
BrigidaD91

Latest Threads

Top