Reputation: 453
when doing
#include <string>
class MyString : public std::string
{
public:
MyString() {}
};
But the usage below:
MyString s = "Happy day";
MyString s("Happy Day");
MyString s = (MyString)"Happy day";
neither of them works.
It seems that there's something to do with constructors/operators declaration/overridding, but can anyone help point out where may I find these resources?
Thanks.
Upvotes: 5
Views: 3916
Reputation: 59807
std::string
isn't designed for inheritance. It doesn't have any virtual functions (not even the destructor!), so you can't override anything. It also doesn't have a protected interface, so you gain nothing from subclassing that you couldn't get by making some standalone utility functions that take std::string
.
Keep in mind that most STL implementations expect you to use std::string
with copy semantics, not reference semantics, and this makes the case for adding inherited fields or overriding functions even weaker.
If you really want something like std::string
with extra functions, you could consider using composition instead of inheritance, but this isn't great either. You don't have to worry about the std::string
destructor not getting called properly, but you do end up having to wrap a lot of methods from std::string
that you need, which is tedious. Also, your utility functions will only work with MyString when most code is going to expect std::string
, so it isn't very reusable.
You're better off making some utility functions that take std::string
. Or, if std::string
isn't providing what you need, you should go with some other string implementation that suits your needs. Here are some possibilities that come to mind:
std::rope
. It's in GNU C++, so maybe you can rely on it.Upvotes: 34
Reputation: 7327
The bottom line is that you shouldn't do this. The destructor on std::string
isn't virtual. This means that if you do the following:
std::vector<std::string*> s_vector;
s_vector.push_back(new MyString("Hello"));
s_vector.push_back(new std::string("World"));
const std::vector<std::string*>::iterator s_vector_end = s_vector.end();
std::vector<std::string*>::iterator s = s_vector.begin();
for (; s != s_vector_end; ++s)
{
delete *s; // Error, MyString's destructor will
// not be called, but std::string's!
}
The only way this might be safe is if you don't add members to your string. You might think that you don't need any now, but someone who isn't aware of these issue may come along later (or you, when you've forgotten this advice perhaps) and add one, and then hey presto, you have a difficult to track down memory leak.
Upvotes: 4
Reputation: 229563
You need to define some constructors for the different types that you want to be able to convert into your strings. These constructors can basically just hand the parameters through to the underlying std::string
.
If you don't manually create them, the compiler creates a default- and a copy-constructor for you:
MyString() : std::string() { }
MyString(const MyString &other) : std::string(other) { }
To allow construction from string literals, you need a constructor that takes a const char*
:
MyString(const char* other) : std::string(other) { }
A constructor that takes a const std::string&
would also be useful to convert std::string
s to your string type. If you want to avoid implicit conversions of normal strings, you should make it explicit
:
explicit MyString(const std::string &other) : std::string(other) { }
(Edited because my original version was full of errors and I can't delete the accepted answer)
Upvotes: 6
Reputation: 112346
You're defining a ctor MyString that takes no arguments. If overrides the other ctors, so there's no ctor taking a string argument at all.
You need to ctor of one argument of type const char *
, something like
MyString(const char * s): std::string(s){}
(Don't trust the syntax, look it up; I don't write C++ every day any longer.)
Check the section in the C++ FAQ Lite on ctors.
(Oops. Const char *, not string. Told you I didn't write C++ every day.)
Upvotes: 1
Reputation: 90422
std::string isn't intended to be inherited from. It doesn't have any virtual methods so you can't override any of its methods.
You should look into composition. Or simply creating utility functions which operate on std::strings
Upvotes: 3
Reputation: 5279
The problem is that you need to overload the constructor that takes const char* and call the base class constructor as follows:
class MyString : public std::string {
public:
MyString() {}
MyString( const char* c ) : std::string( c ) {}
};
All three of your tests should work then.
Upvotes: 3