For Programmers: Free Programming Magazines  


Home > Archive > VC STL > August 2005 > extend/subclass ?









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author extend/subclass ?
Lisa Pearlson

2005-08-02, 10:03 pm

Hi,

Imagine I want to extend std::string to include a function that performs
case-insensitive comparison (icompare), shouldn't I be able to just subclass
it like any other class?

The confusing part for me is that you can use it with templates, if I'm not
mistaken, like this:

std::string<CHAR> string1;

or just

std::string string1;


But I can't seem to subclass like this:

class mystring : public std::string
{
public:
int icompare(const mystring & s) {
// icompare code
return iResult;
}
}

not sure what template the provide. The source code of the std classes are
quite hard to read, using short cryptic variables like _L and " ? : "
instead of if/then/else.

Also, PHP language has the = = operator and the = = = operator. While it's
not used entirely the same way, I think it would be pretty handy to have '=
=' for case insensitive comparison, and '= = =' for case sensitive. But it
looks like C++ doesn't allow '= = =' to be overloaded. I was hoping I could
declare new operators such as #@ or --=-- or whatever combination of
characters that is unique and doesn't conflict with any other meaning it
might have in the language itself. Guess not.

Lisa


Simon Trew

2005-08-02, 10:03 pm

I believe the standard answer is "C++ Standard Library classes are not
intended to be subclassed".

Provide your case-insensitive comparison as an ordering predicate. Make sure
it obeys strict weak ordering (many don't).

S.


Lisa Pearlson

2005-08-02, 10:03 pm

what's strict weak ordering?

This is what I found somewhere, that specifically doesn't use
transform(begin(), end(), begin(), toUpper) and should be more efficient:

int static icompare(const string & s1, const string & s2)
{
wstring::const_iterator it1=s1.begin();
wstring::const_iterator it2=s2.begin();
while ( (it1!=s1.end()) && (it2!=s2.end()) )
{
if(::toupper(*it1) != ::toupper(*it2))
return (::toupper(*it1) < ::toupper(*it2)) ? -1 : 1;
++it1;
++it2;
}
size_t size1=s1.size(), size2=s2.size();
if (size1==size2)
return 0;
return (size1<size2) ? -1 : 1;
}


"Simon Trew" <ten.enagro@werts> wrote in message
news:Oazu597lFHA.3256@tk2msftngp13.phx.gbl...
>I believe the standard answer is "C++ Standard Library classes are not
>intended to be subclassed".
>
> Provide your case-insensitive comparison as an ordering predicate. Make
> sure it obeys strict weak ordering (many don't).
>
> S.
>



Lisa Pearlson

2005-08-02, 10:03 pm

U have seen someone subclass it thoug like this:

namespace MySpace
{
///////
class mystring : public std::string
{
public:
int icompare(const mystring & s1, const mystring &2) const;
}
/////////
}

MySpace::mystring s1("hello"), s2("HELLO");

if (s1.icompare(s2) == 0)
{
// same
}

"Simon Trew" <ten.enagro@werts> wrote in message
news:Oazu597lFHA.3256@tk2msftngp13.phx.gbl...
>I believe the standard answer is "C++ Standard Library classes are not
>intended to be subclassed".
>
> Provide your case-insensitive comparison as an ordering predicate. Make
> sure it obeys strict weak ordering (many don't).
>
> S.
>



Lisa Pearlson

2005-08-02, 10:03 pm

I subclassed like this:

class mystring : public std::string
{
// ...
}

I had to create constructors and assignment operators for 'mystring'.

But the base class std::string contains many functions that return a
std::string such as 'substr'.
Does this mean I have to write a wrapper for each one of them like so:

mystring substr(size_t s, size_t e=npos)
{
return mystring( std::string.substr(s, e));
}

???

lisa

"Lisa Pearlson" <no@spam.plz> wrote in message
news:OWAcA37lFHA.3316@TK2MSFTNGP14.phx.gbl...
> Hi,
>
> Imagine I want to extend std::string to include a function that performs
> case-insensitive comparison (icompare), shouldn't I be able to just
> subclass it like any other class?
>
> The confusing part for me is that you can use it with templates, if I'm
> not mistaken, like this:
>
> std::string<CHAR> string1;
>
> or just
>
> std::string string1;
>
>
> But I can't seem to subclass like this:
>
> class mystring : public std::string
> {
> public:
> int icompare(const mystring & s) {
> // icompare code
> return iResult;
> }
> }
>
> not sure what template the provide. The source code of the std classes are
> quite hard to read, using short cryptic variables like _L and " ? : "
> instead of if/then/else.
>
> Also, PHP language has the = = operator and the = = = operator. While it's
> not used entirely the same way, I think it would be pretty handy to have
> '= =' for case insensitive comparison, and '= = =' for case sensitive. But
> it looks like C++ doesn't allow '= = =' to be overloaded. I was hoping I
> could declare new operators such as #@ or --=-- or whatever combination of
> characters that is unique and doesn't conflict with any other meaning it
> might have in the language itself. Guess not.
>
> Lisa
>
>



Bo Persson

2005-08-03, 4:02 am


"Lisa Pearlson" <no@spam.plz> skrev i meddelandet
news:OrbrqJ8lFHA.2080@TK2MSFTNGP14.phx.gbl...
> what's strict weak ordering?
>
> This is what I found somewhere, that specifically doesn't use
> transform(begin(), end(), begin(), toUpper) and should be more
> efficient:
>
> int static icompare(const string & s1, const string & s2)
> {
> wstring::const_iterator it1=s1.begin();
> wstring::const_iterator it2=s2.begin();
> while ( (it1!=s1.end()) && (it2!=s2.end()) )
> {
> if(::toupper(*it1) != ::toupper(*it2))
> return (::toupper(*it1) < ::toupper(*it2)) ? -1 : 1;
> ++it1;
> ++it2;
> }
> size_t size1=s1.size(), size2=s2.size();
> if (size1==size2)
> return 0;
> return (size1<size2) ? -1 : 1;
> }
>


This will work, for one definition of case insensitive. But toupper is
only defined for characters in the range 0-127, so for most european
languages it will not work. Could be a problem!


Bo Persson


Bo Persson

2005-08-03, 4:02 am


"Lisa Pearlson" <no@spam.plz> skrev i meddelandet
news:us44RL8lFHA.2920@TK2MSFTNGP14.phx.gbl...
>U have seen someone subclass it thoug like this:
>
> namespace MySpace
> {
> ///////
> class mystring : public std::string
> {
> public:
> int icompare(const mystring & s1, const mystring &2) const;


This isn't the member you call below!

Member functions have an implict 'this' parameter that you don't
specify. So this function would look more like

int compare(const mystring& other) const;

> }
> /////////
> }
>
> MySpace::mystring s1("hello"), s2("HELLO");
>
> if (s1.icompare(s2) == 0)
> {
> // same
> }
>


You can also use your icompare as a free function, and call it like

if (icompare(s1, s2) == 0)
{
// same
}


That is much easier!


Bo Persson


Tom Widmer [VC++ MVP]

2005-08-03, 4:02 am

Lisa Pearlson wrote:
> I subclassed like this:
>
> class mystring : public std::string
> {
> // ...
> }
>
> I had to create constructors and assignment operators for 'mystring'.
>
> But the base class std::string contains many functions that return a
> std::string such as 'substr'.
> Does this mean I have to write a wrapper for each one of them like so:
>
> mystring substr(size_t s, size_t e=npos)
> {
> return mystring( std::string.substr(s, e));
> }
>
> ???


You're seeing why it just isn't a good idea to try to replace a
_standard_ type with your own non-standard variant - you end up with
inefficient conversions between the two types all over the place.
Instead, just add the extra functionality with a namespace scope
function, which takes much less typing in any case!

Tom
Lisa Pearlson

2005-08-03, 5:07 pm

That's what I had before but didn't like it.. because it defeats OO design
:)

"Bo Persson" <bop@gmb.dk> wrote in message
news:%23$bTCKAmFHA.2060@tk2msftngp13.phx.gbl...
> You can also use your icompare as a free function, and call it like
>
> if (icompare(s1, s2) == 0)
> {
> // same
> }
>
>
> That is much easier!
>
>
> Bo Persson
>
>



Lisa Pearlson

2005-08-03, 5:07 pm

What do you mean "add extra functionality with a namespace scope function" ?

how do I change my icompare in the way you suggest? no subclassing at all?
just like this:

namespace myfunc
{

int icompare(const string & s1, const string & s2) const
{
// ...
return iResult;
}

};

string s1 = _T("hello");
string s2 = _T("HELLO");

if ( myfunc::icompare(s1, s2) == 0) { .... }


What's the point of using a namespace instead of regular function? Just not
to conflict with other global functions?


"Tom Widmer [VC++ MVP]" <tom_usenet@hotmail.com> wrote in message
news:OK52DfAmFHA.3120@TK2MSFTNGP09.phx.gbl...
> You're seeing why it just isn't a good idea to try to replace a _standard_
> type with your own non-standard variant - you end up with inefficient
> conversions between the two types all over the place. Instead, just add
> the extra functionality with a namespace scope function, which takes much
> less typing in any case!
>
> Tom



Carl Daniel [VC++ MVP]

2005-08-03, 5:07 pm

Lisa Pearlson wrote:
> What do you mean "add extra functionality with a namespace scope
> function" ?
> how do I change my icompare in the way you suggest? no subclassing at
> all? just like this:
>
> namespace myfunc
> {
>
> int icompare(const string & s1, const string & s2) const
> {
> // ...
> return iResult;
> }
>
> };
>
> string s1 = _T("hello");
> string s2 = _T("HELLO");
>
> if ( myfunc::icompare(s1, s2) == 0) { .... }


Yes.

> What's the point of using a namespace instead of regular function?
> Just not to conflict with other global functions?


Yes.

To be clear, there is no difference - a "globasl function" is simply a
namespace scoped function that's in the global namespace.

-cd


Bo Persson

2005-08-03, 5:07 pm


"Lisa Pearlson" <no@spam.plz> skrev i meddelandet
news:ejogwLEmFHA.572@TK2MSFTNGP15.phx.gbl...
> That's what I had before but didn't like it.. because it defeats OO
> design :)


Sort of.

But arguably the "case insensitiveness" is perhaps not a property of
the string itself, but a property of the environment where the string
is used? If you carry on this for a while, and try languages other
than english, you will find all kinds of interesting cases like
accented characters, characters that have only one case, and other
interesting things.

Just a warning. :-)


Bo Persson


>
> "Bo Persson" <bop@gmb.dk> wrote in message
> news:%23$bTCKAmFHA.2060@tk2msftngp13.phx.gbl...
>
>



Stephen Howe

2005-08-03, 5:07 pm

> That's what I had before but didn't like it.. because it defeats OO design
> :)


You might be interested in Herb Sutter's article
http://www.gotw.ca/gotw/029.htm
This is also in his book "Exceptional C++" which also contains some expert
constructive criticism to his solution - worth reading and thinking about.

How would you cope with lowercasing Gr?
The letter 's' is a different character if at the end of a sentence compared
to an 's' in the middle of a sentence.

Or uppercasing German?
"ss" (2 characters) now becomes what looks like a Gr Beta (1 character).

:)

S


Igor Tandetnik

2005-08-03, 5:07 pm

Stephen Howe <stephenPOINThoweATtns-globalPOINTcom> wrote:
> Or uppercasing German?
> "ss" (2 characters) now becomes what looks like a Gr Beta (1
> character).


It's the other way round. A "sharp s" ? only exists in lowercase, and
turns into SS in uppercase. The reverse conversion is difficult without
a dictionary, since some words are spelled with "ss" while others with
sharp-s.

See also
http://en.wikipedia.org/wiki/%C3%9F
http://en.wikipedia.org/wiki/German_spelling_reform

--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925


Lisa Pearlson

2005-08-04, 4:06 am

Yeah, nobody mentions chinese.. (?)

I'm using the case insensitive compare for XML parsing
want to make sure that "true" is same as "True" and "TRUE"
or "pop3" and "POP3" etc.

Just because it doesn't work for all character sets doesn't mean it
shouldn't be implemented.
In cases where there is no toupper conversion, it should simply not do
anything, but convert all other characters.


Tom Widmer [VC++ MVP]

2005-08-04, 9:07 am

Lisa Pearlson wrote:
> What do you mean "add extra functionality with a namespace scope function" ?
>
> how do I change my icompare in the way you suggest? no subclassing at all?


Right.

> just like this:
>
> namespace myfunc
> {
>
> int icompare(const string & s1, const string & s2) const


Lose the const on the end.

> {
> // ...
> return iResult;
> }
>
> };
>
> string s1 = _T("hello");
> string s2 = _T("HELLO");


If you're using _T you'll need to use something like tstring
(typedef std::basic_string<TCHAR> tstring;).

> if ( myfunc::icompare(s1, s2) == 0) { .... }
>
>
> What's the point of using a namespace instead of regular function? Just not
> to conflict with other global functions?


Right - it's generally good practice, but, as Carl said, global
functions are namespace scope functions in any case. I probably should
have said "add extra functionality with a non-member function" to avoid
confusion. In an ideal world, C++ classes should have quite lean
interfaces (to give fewer functions access to the private parts of the
class), and all the convenience fluff should generally be added as
non-member functions in the same namespace as the class (which have no
access to the privates, so don't need to change when the implementation
of the class changes).

Tom
Lisa Pearlson

2005-08-05, 4:02 am

So I should be able to do:

namespace std
{
int icompare ( ... )
{
}
};

Or perhaps even
namespace std::string
{
int icompare ( ... )
{
}
}

I think compiler complains that namespace std already exists.

Lisa


"Tom Widmer [VC++ MVP]" <tom_usenet@hotmail.com> wrote in message
news:u4JaL$NmFHA.3568@tk2msftngp13.phx.gbl...
> Lisa Pearlson wrote:
>
> Right.
>
>
> Lose the const on the end.
>
>
> If you're using _T you'll need to use something like tstring
> (typedef std::basic_string<TCHAR> tstring;).
>
>
> Right - it's generally good practice, but, as Carl said, global functions
> are namespace scope functions in any case. I probably should have said
> "add extra functionality with a non-member function" to avoid confusion.
> In an ideal world, C++ classes should have quite lean interfaces (to give
> fewer functions access to the private parts of the class), and all the
> convenience fluff should generally be added as non-member functions in the
> same namespace as the class (which have no access to the privates, so
> don't need to change when the implementation of the class changes).
>
> Tom



Bo Persson

2005-08-05, 4:02 am


"Lisa Pearlson" <no@spam.plz> skrev i meddelandet
news:eFzQ5VXmFHA.2904@TK2MSFTNGP14.phx.gbl...
> So I should be able to do:
>
> namespace std
> {
> int icompare ( ... )
> {
> }
> };
>


This would work, but is not really allowed by the standard. You may
add template specializations for user defined types, but not much
else. Namespace std is reserved to the implementation.

> Or perhaps even
> namespace std::string
> {
> int icompare ( ... )
> {
> }
> }


This is better, but std::string is not a namespace, so it doesn't work
either.

namespace lisa
{
int icompare(const std::string&, const std::string&);
}

would be ok.

>
> I think compiler complains that namespace std already exists.


Unlike a class, a namespace can be re-opened to add more to it.

namespace a
{
int x;
}

namespace a
{
int y;
}

would put both x and y in namespace a.

If you think about it, this is exactly what the standard library
does - it splits namespace std over a lot of different files.


Bo Persson


>
> Lisa
>
>
> "Tom Widmer [VC++ MVP]" <tom_usenet@hotmail.com> wrote in message
> news:u4JaL$NmFHA.3568@tk2msftngp13.phx.gbl...
>
>



Lisa Pearlson

2005-08-05, 4:02 am

Thank you. You've helped me a lot.

"Bo Persson" <bop@gmb.dk> wrote in message
news:%23o0U8KZmFHA.1044@tk2msftngp13.phx.gbl...
>
> "Lisa Pearlson" <no@spam.plz> skrev i meddelandet
> news:eFzQ5VXmFHA.2904@TK2MSFTNGP14.phx.gbl...
>
> This would work, but is not really allowed by the standard. You may add
> template specializations for user defined types, but not much else.
> Namespace std is reserved to the implementation.
>
>
> This is better, but std::string is not a namespace, so it doesn't work
> either.
>
> namespace lisa
> {
> int icompare(const std::string&, const std::string&);
> }
>
> would be ok.
>
>
> Unlike a class, a namespace can be re-opened to add more to it.
>
> namespace a
> {
> int x;
> }
>
> namespace a
> {
> int y;
> }
>
> would put both x and y in namespace a.
>
> If you think about it, this is exactly what the standard library does - it
> splits namespace std over a lot of different files.
>
>
> Bo Persson
>
>
>
>



Adrian

2005-08-12, 5:05 pm


"Lisa Pearlson" <no@spam.plz> wrote in message
news:OWAcA37lFHA.3316@TK2MSFTNGP14.phx.gbl...
> Hi,
>
> Imagine I want to extend std::string to include a function that performs
> case-insensitive comparison (icompare), shouldn't I be able to just

subclass
> it like any other class?


Don't subclass, basic_string takes a char_traits template argument, create
your own and provide the a compare member that does the case-insensitive
comparsion. This way you'll have all the benefits of basic_string including
all the overloaded constructors and the == operator and you don't have to
rely on the implementation details of the string class.

Adrian


Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com