Hello,
Could someone explain to me why the Standard conveners chose to typedef
std::string rather than derive it from std::basic_stri ng<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_typ e const & other)
: base_type(other ) {}
explicit String(allocato r_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_ty pe const * ptr, size_type count)
: base_type(ptr, count) {}
String(value_ty pe const * ptr, size_type count, allocator_type const & al)
: base_type(ptr, count, al) {}
String(value_ty pe const * ptr)
: base_type(ptr) {}
String(value_ty pe const * ptr, allocator_type const & al)
: base_type(ptr, al) {}
String(size_typ e count, value_type ch)
: base_type(count , ch) {}
String(size_typ e 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::oper ator=(ptr); }
String & operator=(value _type ch)
{ base_type::oper ator=(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;
}
Could someone explain to me why the Standard conveners chose to typedef
std::string rather than derive it from std::basic_stri ng<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_typ e const & other)
: base_type(other ) {}
explicit String(allocato r_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_ty pe const * ptr, size_type count)
: base_type(ptr, count) {}
String(value_ty pe const * ptr, size_type count, allocator_type const & al)
: base_type(ptr, count, al) {}
String(value_ty pe const * ptr)
: base_type(ptr) {}
String(value_ty pe const * ptr, allocator_type const & al)
: base_type(ptr, al) {}
String(size_typ e count, value_type ch)
: base_type(count , ch) {}
String(size_typ e 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::oper ator=(ptr); }
String & operator=(value _type ch)
{ base_type::oper ator=(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;
}
Comment