3

I've read a number of similar questions here but I'm still uncertain of the answer. I understand that deriving from STL classes is discouraged but std::basic_string seems like a good candidate.

The problem I face is that g++ is throwing a fit because std::basic_string does not have a virtual destructor. Why isn't it virtual? Doesn't std::string derive from it?

One attempt:

class string_t :
  private std::basic_string<char>
{
public:
   string_t() :
      basic_string<value_type>() {}

   string_t(
      const basic_string<value_type>& s) :
         basic_string<value_type>(s) {}

   virtual ~string_t() {}
};

Another attempt:

class string_t :
   public std::basic_string<char>
{
public:
   virtual ~string_t();
};

Both throw this warning when compiling with -Weffc++:

warning: base class 'class std::basic_string' has a non-virtual destructor

Zhro
  • 2,546
  • 2
  • 29
  • 39
  • 3
    `std::string` is `std::basic_string` with the character type being `char`, not a derived class. You can't derive from a template because a template is not a type. You're actually deriving from `std::string` here. – chris Apr 08 '15 at 13:37
  • 4
    `std::string` is a typedef, not a derived class. And no, deriving from either is not okay. – Konrad Rudolph Apr 08 '15 at 13:39
  • " STL classes is discouraged but std::basic_string" I thought this is correct, until recently someone clarified to me that it is completely ok to privately inherit from e.g. std::vector. I am not 100% sure, but I guess this is the case in general: stl classes are not meant to serve as public base class. (Looking forward to get corrections in case this is also not quite right) – 463035818_is_not_an_ai Apr 08 '15 at 13:40
  • What version of g++ are you using? I compiled the private inheritance sample with 4.9.2 and it did *not* issue a warning with `-Weffc++`. [coliru](http://coliru.stacked-crooked.com/a/70db9cd1248af08e) – eerorika Apr 08 '15 at 13:43
  • 1
    FWIW, keeping in mind this was from 2012, [this answer](http://stackoverflow.com/a/11529328/962089) explains that `-Weffc++` has several issues and [the comment](http://stackoverflow.com/questions/11496942/understanding-weffc#comment21012182_11529328) beneath it points out this one specifically (for the private inheritance). In any case, remember that inheritance, private or public, causes extreme coupling between two classes. If there is a different feasible solution, like composition, it is often preferred. – chris Apr 08 '15 at 13:47
  • 1
    Why would you want to do something like that anyway? – sbabbi Apr 08 '15 at 15:04
  • Reiterating: There is no good reason to *inherit* from std::string. Inheriting means you guarantee to support the entire interface flawlessly. I am certain that your purposes will be better served with encapsulation (i.e. you support only your own interface and use std::string as an internal building block). – Richard Hodges Apr 08 '15 at 15:39

1 Answers1

3

Well, STL classes have not been designed to be inherited. The major issue with inheriting std::string and others is that they don't have a virtual destructor. That's a big no-no for a base class of public inheritance, as the warning makes clear. It's not nearly as dangerous for private inheritance, though.

There's a bug report for not issuing an error in the case of privately inheriting a base class that has nonvirtual destructor. It hasn't been marked fixed, however my test shows that no warning is issued in g++ 4.9.2 with private inheritance.

Also, a comment in the bug shows how to shoot yourself the foot with (intentionally?) bad code:

class Foo {
public:
    ~Foo() {}
    virtual void f() { }
};

class Bar : private Foo {
public:
    Foo* get() { return this; }
};

int main()
{
    Bar* b = new Bar;
    delete b->get();
}

Privately inheriting a class with nonvirtual destructor is not bad as such if you avoid exposing the inheritance relationship outside the class like in the snippet above. Without going into detail of how you're going to use the inheritance, it's not possible to say if that's the best approach.

Doesn't std::string derive from it?

No, std::string is an alias of std::basic_string<char>.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • FTR, GCC 12 does warn now, with `-Wall`. However, worth adding to the (otherwise nice) answer that the problem here is not the missing `virtual ~Foo` or the pointer "mismatch" itself _directly_. In fact, despite being wonky, there's nothing _actually_ wrong with the example above -- because `Bar` has no dynamic resources and/or an overridden `virtual f` to mess with that data. Also, if `f` was made non-virtual, GCC would even stop complaining, as `Foo` is no longer polymorphic! Neither are the STL template classes, like `string`. – Sz. Apr 25 '23 at 20:05