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.
In inheritance, the derived class inherits all the members(fields, methods) of the base class, but derived class cannot inherit the constructor of the base class because constructors are not the members of the class.
There can't be any proper inheritance of constructors in C++, because the constructor of a derived class needs to perform additional actions that a base-class constructor does not have to do and does not know about.
Constructor is a block of code that allows you to create an object of class and has same name as class with no explicit return type. If we define Parent class constructor inside Child class it will give compile time error for return type and consider it a method.
If we inherit a class from another class and create an object of the derived class, it is clear that the default constructor of the derived class will be invoked but before that the default constructor of all of the base classes will be invoke, i.e the order of invocation is that the base class's default constructor ...
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.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)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With