1

I'm currently a high school student working on a project that requires inheritance. My partner and I wanted to make a class that can inherit and do all the methods of the string class, while we tack on our own. However, we are not particularly sure how to specify that when we want an inherited function called, we want it to be done with our data members. Example:

Class string2: string
{
    public:
    string2(string str) 
    {
        stuff = str;
    }
    private:
        string stuff;
}
main
{ 
    string2 word ("Hello");
    word.substr(0, 1); 
}

If we were to use that function (assuming that it uses proper syntax, that was just a rough sketch), what would we need to do have have the answer appear as "H". Thanks

jmoerdyk
  • 5,544
  • 7
  • 38
  • 49
user2255853
  • 73
  • 1
  • 6
  • 1
    I don't think you need *both* inheritance and a string data member. It should be one or the other, bearing in mind that `std::string` isn't designed for public inheritance (private inheritance, as in your example, might be tolerable.) – juanchopanza Oct 15 '14 at 23:40
  • 1
    You're privately inheriting, which is an ugly form of composition. std::string doesn't have a virtual destructor, so any attempt at public inheritance could lead to disaster. Furthermore, you also have a string data member in addition to the private inheritance. That's wasteful. Just write a wrapper around it with your added functionality. – orfdorf Oct 15 '14 at 23:42
  • @SchizoidSpag It would be harder for private inheritance to cause a disaster. – juanchopanza Oct 15 '14 at 23:43
  • True, but it's obvious the OP doesn't even know what private inheritance is doing either. – orfdorf Oct 15 '14 at 23:44
  • 1
    @SchizoidSpag That is likely. But it could be a relatively safe way to get the "stuff" without too much typing :-) – juanchopanza Oct 15 '14 at 23:45
  • @SchizoidSpag That's where `using` comes in. – juanchopanza Oct 15 '14 at 23:47
  • To OP: the cleanest way to extend `std::string`'s functionality is to provide non-member functions. `std::string` already has too many member functions. – juanchopanza Oct 15 '14 at 23:49
  • 2
    @SchizoidSpag Since forever: http://ideone.com/VeZqHE – juanchopanza Oct 15 '14 at 23:50
  • http://stackoverflow.com/questions/6006860/why-should-one-not-derive-from-c-std-string-class – Neil Kirk Oct 16 '14 at 00:25
  • @SchizoidSpag It is a well known idiom. It isn't that atrocious. In fact, there is very little wrong with it. – juanchopanza Oct 16 '14 at 06:06
  • 2
    @juanchopanza I definitely did *not* know about this idiom, so thank you for that! – borrrden Oct 16 '14 at 10:07

1 Answers1

3

You're privately inheriting from std::string. Private inheritance means nobody else knows about the inheritance. This means that nobody will be able to treat your string2 like an std::string, because the std::string portion is private. It's basically just an ugly form of composition. If you think that public inheritance solves your problem, think again. std::string's destructor is not virtual.

Furthermore, in addition to your private inheritance, you also have an std::string data member. This is redundant, as your string2 class already inherited all the members of std::string. If you want to extend the functionality of std::string, you have a few options.

You can either wrap it (no inheritance, store a std::string data member, and tunnel function calls to it):

class string2
{
public:
    void push_back(char _ch)
    {
        mString.push_back(_ch);
    }

private:
    std::string mString;
};

Or you can wrap it (private inheritance, no std::string data member, and still tunnel function calls to it):

class string2 : private std::string
{
public:
    void push_back(char _ch)
    {
        std::string::push_back(_ch);
    }

};

Or you can write non-member utility functions that manipulate it, and bundle them in a namespace:

namespace string2
{
    char GetFirstLetter(const std::string& str)
    {
        // blah blah
    }
}

Bonus mention by juan: You can also write this ugliness if you never want to pass a code review:

class string2 : private std::string
{
public:
    using std::string::push_back;
};

Note that push_back() is just for example. You'd need to do this for every member of std::string you want exposed.

orfdorf
  • 980
  • 9
  • 13
  • I kind of think the private inheritance method with the `using` directives is a lot less ugly than writing a forwarding function for each overloaded method in the string's interface (and a lot less work). – Galik Oct 16 '14 at 00:26
  • Thank you very much. As I said I am high school, and my teacher didn't go over this. I don't know why he allowed us to do this when we first proposed the idea, but I'll make sure to pass this along to the rest of my group. Again, thank you so so very much – user2255853 Oct 16 '14 at 00:28
  • Just noticed the responses. @Galik: The private inheritance method with the using directive may be easier to write, but don't forget that it also requires that you `#include` string in your header for `string2`, exposing `string` to everything that uses `string2`, whereas the wrapper methods can avoid this with aggregation and/or pImpl idioms. – orfdorf Oct 13 '15 at 04:49