473,243 Members | 1,562 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,243 software developers and data experts.

class String : public std::string {}; ????

Hello,

Could someone explain to me why the Standard conveners chose to typedef
std::string rather than derive it from std::basic_string<char, ...>?

The result of course is that it is effectively impossible to forward declare
std::string. (Yes I am aware that some libraries have a string_fwd.h header,
but this is not portable.)

That said, is there any real reason why I can't derive an otherwise empty
String class from std::string? Will there be any hidden surprises? As I
understand it, the fact that String has no member variables of its own means
that the non-virtual std::string destructor is not an issue.

Nonetheless, I'm wary because I have heard so much about 'std::string is not
designed to be derived from'. Nobody has explained the rationale behind such
a statement to me however.

Below is sample code that appears to work just fine.

Best regards,
Angus

#ifndef FWD_DECLARABLE_STRING_H
#define FWD_DECLARABLE_STRING_H

#include <string>

struct String : public std::string {
typedef std::string base_type;

String() {}
String(base_type const & other)
: base_type(other) {}
explicit String(allocator_type const & al)
: base_type(al) {}
String(String const & other, size_type off, size_type count = npos)
: base_type(other, off, count) {}
String(String const & other, size_type off, size_type count,
allocator_type const & al)
: base_type(other, off, count, al) {}
String(value_type const * ptr, size_type count)
: base_type(ptr, count) {}
String(value_type const * ptr, size_type count, allocator_type const & al)
: base_type(ptr, count, al) {}
String(value_type const * ptr)
: base_type(ptr) {}
String(value_type const * ptr, allocator_type const & al)
: base_type(ptr, al) {}
String(size_type count, value_type ch)
: base_type(count, ch) {}
String(size_type count, value_type ch, allocator_type const & al)
: base_type(count, ch, al) {}
template <typename InIt>
String(InIt first, InIt last)
: base_type(first, last) {}
template <typename InIt>
String(InIt first, InIt last, allocator_type const & al)
: base_type(first, last, al) {}

String & operator=(value_type const * ptr)
{ base_type::operator=(ptr); }
String & operator=(value_type ch)
{ base_type::operator=(ch); }
};

#endif // FWD_DECLARABLE_STRING_H

#include <iostream>

int main()
{
String const angus = "angus";
std::string const jmarc = "jmarc";
String test1;
std::string test2;

// Assign a std::string to a String
test1 = jmarc;
std::cout << "test1 " << test1 << std::endl;

// Assign a String to a std::string
test2 = angus;
std::cout << "test2 " << test2 << std::endl;

// Assign a String to a String (implicit assignment operator)
test1 = angus;
std::cout << "test1 " << test1 << std::endl;

// Implicit copy c-tor;
String const test3 = angus;
std::cout << "test3 " << test3 << std::endl;

// Copy construct a std::string from a String
std::string test4 = angus;
std::cout << "test4 " << test4 << std::endl;

return 0;
}

Jul 19 '05 #1
10 8113
Angus Leeming <an***********@btopenworld.com> writes:
Hello,

Could someone explain to me why the Standard conveners chose to typedef
std::string rather than derive it from std::basic_string<char, ...>?

The result of course is that it is effectively impossible to forward declare
std::string. (Yes I am aware that some libraries have a string_fwd.h header,
but this is not portable.)

That said, is there any real reason why I can't derive an otherwise empty
String class from std::string?
There are two issues.

(a) No virtual destructor. This means you can't safely call delete on
a pointer to string when the object pointed to is in fact a
derived_from_string.

(b) It isn't designed for polymorphism. (Like most of the standard
library.) Public inheritance is usually used for
polymorphism. Note (a) is a symptom of (b) .

If you somehow know you'll never use the derived_from_string
polymorphically, you won't encounter problems.

However, before proceeding, try private inheritance combined with a
few well-placed using statements. That is safer.

Will there be any hidden surprises?
See above. Further, if people *can* make polymorphic use of your
derived_from_string type, they all too often will.
As I understand it, the fact that String has no member variables of
its own means that the non-virtual std::string destructor is not an
issue.

[snip]

This has nothing to do with it. Calling delete on a pointer to string
is undefined behavior if it in fact points to a
derived_from_string, regardless of whether derived_from_string has
member variables of its own.
Jul 19 '05 #2

"Angus Leeming" <an***********@btopenworld.com> wrote in message news:bj**********@hercules.btinternet.com...

That said, is there any real reason why I can't derive an otherwise empty
String class from std::string? Will there be any hidden surprises? As I
understand it, the fact that String has no member variables of its own means
that the non-virtual std::string destructor is not an issue.


What makes you think it's not an issue? It is undefined behavior to delete
a derived object from a pointer to its base class without a virtual distructor.
It doesn't matter that the derived destructor doesn't do anything or that there
are no data members in the derived class.

Jul 19 '05 #3
Ron Natalie wrote:

"Angus Leeming" <an***********@btopenworld.com> wrote in message
news:bj**********@hercules.btinternet.com...

That said, is there any real reason why I can't derive an otherwise empty
String class from std::string? Will there be any hidden surprises? As I
understand it, the fact that String has no member variables of its own
means that the non-virtual std::string destructor is not an issue.


What makes you think it's not an issue? It is undefined behavior to delete
a derived object from a pointer to its base class without a virtual
distructor. It doesn't matter that the derived destructor doesn't do
anything or that there are no data members in the derived class.


Many thanks to both of you for the clear explanation. I shall put your
arguments to the project moderator who will promptly boot my proposed use of
String into touch ;-)

Thanks again,
Angus
Jul 19 '05 #4
Hi Angus,

| Could someone explain to me why the Standard conveners chose to typedef
| std::string rather than derive it from std::basic_string<char, ...>?

Two reasons I can see:
- If this were done, template code that uses std::basic_string<ACharType>
would be using a different string class than your non-template code ?
Or some special policy classes would be needed...
- If such derivation was used, std::basic_string would need a virtual
destructor.

| The result of course is that it is effectively impossible to forward
declare
| std::string. (Yes I am aware that some libraries have a string_fwd.h
header,
| but this is not portable.)
True. Note that adding such a header yourself is an option even for
implementations that do not support it...

| That said, is there any real reason why I can't derive an otherwise empty
| String class from std::string? Will there be any hidden surprises? As I
| understand it, the fact that String has no member variables of its own
| means that the non-virtual std::string destructor is not an issue.
It *might* not be an issue in most C++ implementations. But formally,
it still does lead to undefined behavior when used improperly.
The following related discussion might be of interest:
http://www.gotw.ca/publications/mill18.htm
| Nonetheless, I'm wary because I have heard so much about 'std::string is
not
| designed to be derived from'. Nobody has explained the rationale behind
such
| a statement to me however.

The public non-virtual destructor remains the key issue.
Another caveat is the too many member functions of std::string,
which may at some point create conflicts...

Most of the time, people who want to derive from std::string also want to
add some state/data members to it (in which case containment is a better
idea, as it allows to enforce class invariants), or add some member
functions (in that case, non-member functions should be preferred).
Public derivation from std::string has serious caveats,
and is often done by novices for these wrong reasons.
And indeed, I have yet to see a good motivation for deriving from
std::string...

| Below is sample code that appears to work just fine.
From a quick look through the code it seems ok and will not invoke UB.
However, is it worth defining your own class just to be
able to forward-declare it ?
Force any maintainers to use an additional non-standard class,
and deal with (even implicit) conversions ?

Personally, if compile-time overhead was a read problem,
would rather implement a custom <string_fwd.h> header for
each platform I am using...
Regards,
Ivan
--
http://ivan.vecerina.com
Brainbench MVP for C++ <> http://www.brainbench.com
Jul 19 '05 #5
On Wed, 10 Sep 2003 15:46:53 +0000 (UTC), Angus Leeming
<an***********@btopenworld.com> wrote:
Hello,

Could someone explain to me why the Standard conveners chose to typedef
std::string rather than derive it from std::basic_string<char, ...>?

The result of course is that it is effectively impossible to forward declare
std::string. (Yes I am aware that some libraries have a string_fwd.h header,
but this is not portable.)
Why do you need to forward declare string? Have you measured an actual
increase in compile time when you #include <string>?

Forward declarations are generally used to decouple code and reduce
dependencies. However, a dependency on std::string isn't a dependency
at all, it is just a use of the language. IOW, since std::string only
changes if you upgrade your compiler (in which case a full recompile
is required anyway), there isn't much to be gained from a forward
declaration.
That said, is there any real reason why I can't derive an otherwise empty
String class from std::string? Will there be any hidden surprises? As I
understand it, the fact that String has no member variables of its own means
that the non-virtual std::string destructor is not an issue.
In practice this is true on most compilers. However, it is dangerous
to rely on it since the standard forbids it.
Nonetheless, I'm wary because I have heard so much about 'std::string is not
designed to be derived from'. Nobody has explained the rationale behind such
a statement to me however.


The idea is that there is generally nothing to be gained from deriving
from std::string, and there is danger (the non-virtual destructor). If
you need to:

1. Add features.
Add them as non-member functions.
2. Add members.
Create a class that contains a string and your extra members or use
private inheritence - typically you won't want the full string
interface anyway (often combined with 3).
3. Add invariants.
You can't use public derivation for this, you must use private
inheritence or containment, since otherwise the invariants can be
broken by accessing the object as a string&.
4. Override behaviour.
Inheritence doesn't work since none of the methods are virtual.
5. Forward declare String (!)
Just #include <string>.

Tom
Jul 19 '05 #6
Ivan Vecerina wrote:
| That said, is there any real reason why I can't derive an otherwise empty
| String class from std::string? Will there be any hidden surprises? As I
| understand it, the fact that String has no member variables of its own
| means that the non-virtual std::string destructor is not an issue.
It *might* not be an issue in most C++ implementations. But formally,
it still does lead to undefined behavior when used improperly.
The following related discussion might be of interest:
http://www.gotw.ca/publications/mill18.htm
Thanks for the pointer.
Most of the time, people who want to derive from std::string also want to
add some state/data members to it (in which case containment is a better
idea, as it allows to enforce class invariants), or add some member
functions (in that case, non-member functions should be preferred).
Understood.
Personally, if compile-time overhead was a read problem,
would rather implement a custom <string_fwd.h> header for
each platform I am using...


Guess what my next proposal to the project is going to be ;-)

Many thanks to you for your time; it is much appreciated.
Regards,
Angus

Jul 19 '05 #7
tom_usenet wrote:
The result of course is that it is effectively impossible to forward declare
std::string. (Yes I am aware that some libraries have a string_fwd.h header,
but this is not portable.)


Why do you need to forward declare string? Have you measured an actual
increase in compile time when you #include <string>?


That's exactly what I am going to do. I am talking about a project (LyX,
www.lyx.org) that takes 26mins on a 2.7GHz machine to do a full compile. It
gets a little wearing at times, so we all start hunting around for
scapegoats. Yeh, I know. We should write decent code in the first place ;-)

Regards,
Angus

Jul 19 '05 #8
llewelly <ll*********@xmission.dot.com> wrote:
The result of course is that it is effectively impossible to forward declare
std::string. (Yes I am aware that some libraries have a string_fwd.h header,
but this is not portable.)

That said, is there any real reason why I can't derive an otherwise empty
String class from std::string?
There are two issues.

(a) No virtual destructor. This means you can't safely call delete on
a pointer to string when the object pointed to is in fact a
derived_from_string.

(b) It isn't designed for polymorphism. (Like most of the standard
library.) Public inheritance is usually used for
polymorphism. Note (a) is a symptom of (b) .

If you somehow know you'll never use the derived_from_string
polymorphically, you won't encounter problems.


Is there a way to make sure that a class will never be used for
inheritance? [I don't think so but I thought I better ask]
However, before proceeding, try private inheritance combined with a
few well-placed using statements. That is safer.


This would make both 'issues' go away, wouldn't it?

So to re-phrase Angus' original question: Why is std::string a typedef
and not _privately_ derived from std::basic_string<char> with a lots of
'using' in it? [The benefit would still be there: to be able to
forward-declare it]

Or, alternatively:

Why isn't there a 'slim' Standard <stringfwd> header?

Andre'

Jul 19 '05 #9
On Wed, 10 Sep 2003 16:57:27 +0000 (UTC), Angus Leeming
<an***********@btopenworld.com> wrote:
tom_usenet wrote:
The result of course is that it is effectively impossible to forward declare
std::string. (Yes I am aware that some libraries have a string_fwd.h header,
but this is not portable.)


Why do you need to forward declare string? Have you measured an actual
increase in compile time when you #include <string>?


That's exactly what I am going to do. I am talking about a project (LyX,
www.lyx.org) that takes 26mins on a 2.7GHz machine to do a full compile. It
gets a little wearing at times, so we all start hunting around for
scapegoats. Yeh, I know. We should write decent code in the first place ;-)


I don't think GCC supports pre-compiled headers, which might help for
system and standard headers. GCC is a very slow compiler though at the
best of times.

Otherwise, it's just a matter of reducing the real dependencies in
your code, so less of your own headers are included in each file.

Tom
Jul 19 '05 #10
André Pönitz <po*****@gmx.net> wrote in message news:<bj**********@anderson.hrz.tu-chemnitz.de>...
Is there a way to make sure that a class will never be used for
inheritance? [I don't think so but I thought I better ask]
http://www.parashift.com/c++-faq-lit....html#faq-23.8
http://www.research.att.com/~bs/bs_f...#no-derivation
However, before proceeding, try private inheritance combined with a
few well-placed using statements. That is safer.


This would make both 'issues' go away, wouldn't it?


Mostly, yes. A private inheritance relationship is known only to the
derived class and its friends, so only they can use it
polymorphically. If they don't use it polymorphically, there is no
problem.
So to re-phrase Angus' original question: Why is std::string a typedef
and not _privately_ derived from std::basic_string<char> with a lots of
'using' in it? [The benefit would still be there: to be able to
forward-declare it]
A few reasons. First and foremost, it wouldn't be a std::basic_string
instantation anymore, so it wouldn't work with templates that expect
std::basic_string. (I'm sure I could come up with other forward
declarations that might do worse.)

Second, it's a hack. I've used private inheritance and using
declarations to implement a new class in terms of an old one. But I'd
never recommend using them to fake forward declarations, certainly not
at the level of the Standard.
Or, alternatively:

Why isn't there a 'slim' Standard <stringfwd> header?


Since we've got <iosfwd>, my guess is that they just forgot to put one
in. Sounds like something to be asked and/or debated on comp.std.c++.
:)

---

Incidentally, you can (depending on your intestinal fortitude)
forward-declare these things yourself. Herb Sutter tells us not to do
it in GOTW 34:

<quote url="http://www.gotw.ca/gotw/034.htm">
The standard says:

It is undefined for a C++ program to add declarations or definitions
to namespace std or namespaces within namespace std unless otherwise
specified.
</quote>

Of course, in the Real World, without which ISO C++ is meaningless,
I'd love to see an implementation which does anything worse than fail
to compile on a forward-declaration of std::string.

Herb continues:

<quote>
Among other things, this allows vendors to provide implementations of
the standard library that have more template parameters for library
templates than the standard requires (suitably defaulted, of course,
to remain compatible).
</quote>

But according to the official ISO C++ closed issues list, they can't:

<quote url="http://std.dkuug.dk/jtc1/sc22/wg21/docs/lwg-closed.html#94">
Library implementors are not permitted to add template parameters to
standard library classes.
</quote>

So, any compiler that doesn't supply the *exact* template interface is
non-conforming. If we know the interface, we ought to be able to
forward-declare it, like so:

namespace std {
template <typename> class char_traits;
template <typename> class allocator;

// cannot use default parameters in the forward declaration
template <typename, typename, typename> class basic_string;

// instead, use them here
typedef std::basic_string<char,
std::char_traits<char>,
std::allocator<char> > string;
}

But since this is heresy in comp.lang.c++, I suppose you're left to
including <string> whenever you need std::string, at least for now.

Better go get some coffee... This could take awhile. :)

- Shane
Jul 19 '05 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Matthias Käppler | last post by:
Hi, I just browsed libstdc++6-doc and stumbled over a string operation I haven't noticed before: string::push_back. If for example I want to append single characters to an std::string, which...
9
by: Jim Langston | last post by:
#include <string> int main () { std::string MyString = "Testing"; MyString = " " + MyString; } This works in Microsoft Visual C++ .net 2003
10
by: cmk128 | last post by:
Hi I am going to implement a new string class for my os, do you have any idea to enhance of standard c++ string class? If compare c++ string class with CS++ CString class and java String class,...
1
by: Wild Wind | last post by:
Hello, I have the following methods I've written to convert from String* to std::string and back: static void ConvertFromStdString(std::string& inStr, System:String* outStr) { outStr = new...
2
by: HerbD | last post by:
I have a loooong debugging session behind me! I finally found the reason for the problem and now would like to know, if it is a bug in my code or not standardconformant behavour of the compiler(s) or...
13
by: Venthor | last post by:
Hello, I'm having some problems wrapping my head around what I need to do. I'm using a vector to store an array of a specific class object full of data. class part_info { public: string...
11
by: Christopher Pisz | last post by:
Is std::string::npos always going to be less than any std::string 's size()? I am trying to handle a replacement of all occurances of a substr, in which the replacement also contains the substr....
8
by: Edson Manoel | last post by:
I have some C++ unmanaged code that takes std::string& arguments (as reference), and fills them (possibly growing the string). I want to call this code through PInvoke (DllImport), possibly using...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: stefan129 | last post by:
Hey forum members, I'm exploring options for SSL certificates for multiple domains. Has anyone had experience with multi-domain SSL certificates? Any recommendations on reliable providers or specific...
1
by: davi5007 | last post by:
Hi, Basically, I am trying to automate a field named TraceabilityNo into a web page from an access form. I've got the serial held in the variable strSearchString. How can I get this into the...
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
by: Aftab Ahmad | last post by:
So, I have written a code for a cmd called "Send WhatsApp Message" to open and send WhatsApp messaage. The code is given below. Dim IE As Object Set IE =...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.