3

Recently, I have been wanting to define a subclass spstring of std::string. It declared in spstr.h:

#include <cctype>
#include <string>
#include <algorithm>
#include <sstream>
#include <stdint.h>
#include <xstring>


class spstring : public std::string {
public:
    spstring(std::string s):std::string(s){}  //Declare the constructor
    int stoi(); //Declare stoi
    spstring Spstring(std::string s); ////Declare mandatory conversion function
};

spstring spstring::Spstring(std::string s)
{
    spstring spstr(s); 
    return(spstr);
}

However, when tested in main.cpp:

spstring byteaddstr(std::string(argv[4])); //convertchar* to spstring
int byteadd;
byteadd=byteaddstr.stoi(); //call byteaddstr.stoi

it failed to be complied for:

error C2228: left of “.stoi” must have class/struct/union

Sounds strange, since byteaddstr indeed an instance of spstring, why cannot call its member function?

Popopo
  • 133
  • 7
  • 8
    You generally don't want to derive from STL containers. – Daniel Kamil Kozar Dec 11 '13 at 07:00
  • 2
    In general, it is considered a bad idea to inherit from `std::string`, especially publicly [(see related SO post)](http://stackoverflow.com/questions/6006860/why-should-one-not-derive-from-c-std-string-class). Private inheritance *might* be considered safe enough, although it still imposes a tight coupling between your class and `std::string`. See an interesting discussion on [abuses of inheritance here](http://www.gotw.ca/publications/mill06.htm). As for the error, please post a short, self-contained example that reproduces the problem. – juanchopanza Dec 11 '13 at 07:10
  • 1
    You don't derive from std::string (or map, or vector, or any other container). In all instances where I encountered this there were several better solutions available. Whenever you need to derive from an stl container, consider encapsulation instead, meaning either using the container as a member of your class, or using private inheritance. – Peter Dec 11 '13 at 07:17
  • Note that passing std::string by value is inefficient, use const reference or move syntax instead. – nyrl Dec 11 '13 at 07:24
  • 1
    With regards to using STL containers to define new types, composition is the best approach than inheritance. See here: http://stackoverflow.com/questions/14089088/are-stl-containers-designed-to-allow-inheritance – yasouser Dec 11 '13 at 07:25
  • @Popopo: See this question to get some perspectives on why composition is preferred to inheritance: http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance – yasouser Dec 11 '13 at 08:17

2 Answers2

5

In C++ any declaration that can be parsed as a function declaration, such as …

    spstring byteaddstr(std::string(argv[4])); //convertchar* to spstring

is parsed as a function declaration.

I.e. not a variable.

One solution in this particular case, is to add extra parentheses:

    spstring byteaddstr(( std::string(argv[4]) )); //convertchar* to spstring

This is known as the most vexing parse in C++, although some people disagree about whether Scott Meyers' original use of that term applies as generally as it's used now.


And by the way, one should generally have a pretty good reason to derive from std::string, because it adds complexity and confusion (you can safely disregard concerns about dynamic allocation, because code that dynamically allocates std::string deserves whatever it gets). So, I suggest that you don't do that.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
1

Inheriting from std::string (and the STL containers) is a bad idea. They are not designed to operate as base classes.

Importantly, they don't necessarily have a virtual destructor so that can make memory management difficult for derived classes.

You would also lose readability too: If I see an STL class or function then I know exactly what is going to happen as it's assumed that I've memorised the standard. With a derived class I have to rely on its documentation or program comments.

So my answer: There is no right way to inherit from std::string.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483