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".
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…