Is it Dangerous to Derive from STD? Specifically std::string.

Why I'm asking?

I want to write a class that extends the functionality of std::string and a couple other std structs/classes.. So that when I do something like:

String M = "";
M.Explode(........) it'll do the functionality in my class below.

Thing is I'm reading that it's very dangerous (on google at least).. and that I should "NEVER DERIVE FROM STD!!!!" because something about the destructor or constructor being virtual sometimes?

For example:

class Strings  :  public std::string
{
    private:
        vector<string> &SplitWrapper(const string &s, char delim, vector<string> &elems)
        {
            stringstream ss(s);
            string item;
            while(getline(ss, item, delim))
            {
                elems.push_back(item);
            }
            return elems;
        }

    public:
        vector<string> Explode(const string &s, char delim)
        {
            vector<string> elems;
            return SplitWrapper(s, delim, elems);
        }

        string Implode(string Glue, string Pieces[])
        {
            int I, Len;
            string Result = "";

            Len = HIGH(Pieces);
            if (Len < 0)
                return Result;
            Result = Pieces[0];
            for (I = 1; I < Len; I++)
                Result += Glue + Pieces[I];
        }

        string Implode(const string &Glue, const vector<string> &Pieces)
        {
            string Str;
            int Len = Pieces.size();
            for(int I = 0; I < Len; I++)
            {
                Str += Pieces[I];
                if (I < (Len - 1))
                    Str += Glue;
            }
            return Str;
        }

        bool isUpper()
        {
            
        }
};

Recommended Answers

All 2 Replies

Is it Dangerous to Derive from STD? Specifically std::string.

As far as I know, no. That's why objects exist. You start with an object that does most of what you want and add more functionality to it for your specific needs.

First things' first, to a large extent, classes in the C++ standard libraries (with the exception of iostreams) are not object-oriented classes, they are not meant to be derived from and they generally don't derive from other base classes from which you could also derive. The iostream library is an exception as it provides an OOP architecture with specific classes that are base-classes from which classes like std::ifstream or std::stringstream are derived, and these base-classes are indeed intended (possibly) to act as base-classes in user-side code (meaning you are "allowed" to derive from these classes). std::string , which is actually just a typedef for the class std::basic_string<char> , is not meant to be derived from or treated as a base-class in any typical OOP sense of the term. It does not (or at least not according to the C++ standard) have a virtual destructor or any other virtual functions for that matter. This means one thing: you will not get polymorphism from inheriting from this class. This is very important, because inheritance is (mostly) about dynamic polymorphism (polymorphism in the OOP sense). To a large extent, if inheritance does not give rise to a polymorphic use of your class, then inheritance is not necessary or useful, and should not be considered a good option.

Is it dangerous? Yes and no. If you assume that you can override existing functions of the string class or have polymorphic pointers to the class (when it actually points to the derived class), then you will be at risk of falling into many pitfalls. If you know what you are doing and don't expect any polymorphic behaviour, and you make it clear in your code-documentation that this derived class is not polymorphic in any real sense of the term, then it won't be dangerous, but it will be useless and, frankly, stupid to do so because you gain no benefit and you have constantly check to make sure you avoid the lurking pitfall.

Class templates like std::basic_string and std::vector are generic classes (or generic containers), which are, by nature, statically polymorphic. The mechanisms by which you extend their functionality or redefine their interfaces are very different from those employed in object-oriented programming.

In any case, wanting to reuse the code that is inside of a class is not a good reason for inheritance (in OOP). The saying goes: Don't inherit to reuse code, inherit to be reused! The preferred route for code-reuse is composition (holding an object of that class inside your new class). There are a few reasons for that.

First, a base-class, like any other class, has a public interface or set of functionality, and this is what is meant to be used, while all implementation details are encapsulated and abstracted away. This means that, by inheriting, you don't gain anything significant from that base-class in terms of code reuse because you still cannot rely on anything it has besides what its public interface prescribes (you cannot and should not access anything else). With composition, you can do the same (although slightly more verbose).

Second, you lack the flexibility to switch to another container or class to store your data, and, similarly, you make an implementation detail (how you actually store your data) very public, which is rarely desirable nor correct.

Third, this practice of inheritance for code-reuse leads to bloated class interfaces, so called monolithic classes (one class with a huge amount of member functions, trying to provide functionality for everything). One of the few criticisms that sometimes befall on the C++ standard classes is exactly that, they tend to be too monolithic (like std::string and most containers). If there is one thing that you shouldn't imitate from looking at C++ standard libraries, it's that habit of creating monolithic classes.

Finally, inheritance is an extremely strong coupling between two classes, which has consequences like the pollution of interface of your class with all the (possibly no longer useful) member functions of the base class. In software design, and that is a very general rule, you must aim for the least amount of coupling as possible. This is why it is generally recommended to have base-classes that are more like the OOP concept of an "interface class" (meaning, few or no data members, and mostly (or all) (pure) virtual member functions).


If you just want to add functionality to the string class, why not use a non-intrusive mechanism? That's the preferred way, as in:

template <typename charT, typename Traits, typename Allocator>
std::vector< std::basic_string<charT, Traits, Allocator> > explode(const std::basic_string<charT, Traits, Allocator>& s, charT delim) {
  //... implementation goes here.
};

//So, you call it as:
vect = explode(s, delim);

// Is the above much worse than below?
vect = s.explode(delim);
// I think not!

With the above, you get the same extended functionality, you can reuse the code of the string class, and you don't run into any danger with respect to creating the illusion that your derived class is polymorphic when it is not.

commented: I stand corrected. Thanks. +17
commented: Superbly argue, thx +9
commented: YOU!!! Always giving me the best answer =] +6
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.