Extending the C++ Standard Library by inheritance?

Solution 1:

Good nice question. I really wish that the Standard was a little more explicit about what the intended usage is. Maybe there should be a C++ Rationale document that sits alongside the language standard. In any case, here is the approach that I use:

(a) I'm not aware of the existence of any such list. Instead, I use the following list to determine whether a Standard Library type is likely to be designed to be inherited from:

  • If it doesn't have any virtual methods, then you shouldn't be using it as a base. This rules out std::vector and the like.
  • If it does have virtual methods, then it is a candidate for usage as a base class.
  • If there are lots of friend statements floating around, then steer clear since there is probably an encapsulation problem.
  • If it is a template, then look closer before you inherit from it since you can probably customize it with specializations instead.
  • The presence of policy-based mechanism (e.g., std::char_traits) is a pretty good clue that you shouldn't be using it as a base.

Unfortunately I don't know of a nice comprehensive or black and white list. I usually go by gut feel.

(b) I would apply LSP here. If someone calls what() on your exception, then it's observable behavior should match that of std::exception. I don't think that it is really a standards conformance issue as much as a correctness issue. The Standard doesn't require that subclasses are substitutable for base classes. It is really just a "best practice".

Solution 2:

a) the stream library is made to be inherited :)

Solution 3:

Regarding your part b, from 17.3.1.2 "Requirements", paragraph 1:

The library can be extended by a C++ program. Each clause, as applicable, describes the requirements that such extensions must meet. Such extensions are generally one of the following:

  • Template arguments
  • Derived classes
  • Containers, iterators, and/or algorithms that meet an interface convention

While 17.3 is informative instead of binding, the committee's intent on derived class behavior is clear.

For other very similar points of extension, there are clear requirements:

  • 17.1.15 "required behavior" covers replacement (operator new, etc.) and handler functions (terminate handlers, etc.) and throws all non-compliant behavior into UB-land.
  • 17.4.3.6/1: "In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ Standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation."

In the last point it's not clear to me that the parenthetical list is exhaustive, but given how specifically each mentioned case is dealt with in the next paragraph, it would be a stretch to say the current text was intended to cover derived classes. Additionally, that 17.4.3.6/1 text is unchanged in the 2008 draft (where it's in 17.6.4.8) and I see no issues addressing either it or derived classes' virtual methods.