I know that std::string is not designed for inheritance, however, I wonder why this class definition doesn't compile:
using std::string;
class ExtendedString: public string
{
public:
using string::string;
ExtendedString left(size_type n) const {
return substr(0, n>size()?size():n);
}
};
I get this error:
../../src/capel-tool.cpp:21:17: error: could not convert ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::substr(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type) const [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int](0, ((n > ((const ExtendedString*)this)->ExtendedString::<anonymous>.std::__cxx11::basic_string<char>::size()) ? ((const ExtendedString*)this)->ExtendedString::<anonymous>.std::__cxx11::basic_string<char>::size() : n))’ from ‘std::__cxx11::basic_string<char>’ to ‘ExtendedString’
I expected that the left
function would use any default constructor from std::string.
Even if I add an explicit constructor like this:
using std::string;
class ExtendedString: public string
{
public:
using string::string;
ExtendedString left(size_type n) const {
return substr(0, n>size()?size():n);
}
explicit ExtendedString(const std::string &s);
};
I still get the same error.
Only when I add a normal constructor:
using std::string;
class ExtendedString: public string
{
public:
using string::string;
ExtendedString(const std::string &s);
ExtendedString left(size_type n) const {
return substr(0, n>size()?size():n);
}
};
The code compiles ok.
Now imagine I want to make the same with a class that is designed for inheritance. Can not I just create this kind of wrapper in a way that the classes can be used interchangeablily without the need to create constructors thad would be created and called instead of being only "syntax sugar"
EDIT 1:
This suggested question does explain why my code does not work, but it does not propose any alternatives, as the accepted question does.
The problem with your code is that substr
returns a std::string
, not an ExtendedString
. No implicit conversion exists between the types, so that return statement cannot compile.
There is an implicit conversion up the inheritance hierarchy, i.e. you can convert ExtendedString
to std::string
, but not the other way around.
To solve this for just your left
function:
ExtendedString(const std::string&)
return ExtendedString(substr(...))
However, in general, what you're trying to do is just not nicely possible in C++. Every member function that you inherit from std::string
is not going to return ExtendedString
, so you have the wrong interface. C++ gives you no way of defining extension methods, which is the feature you're imitating.
std::string
to ExtendedString
, but this results in unnecessary copying
ExtendedString(const std::string &s);
std::string
or better yet, wrap it as a member
std::string
has, and make them take/return ExtendedString
where necessarystd::string left(const std::string& s, std::size_t n) {
return s.substr(0, std::min(s.size(), n));
}
As annoying as it is to sometimes call str.function()
and sometimes function(str)
, that inconsistency is a small price compared to any alternative.