> > That's generally excellent advice in runtime polymorphic
> > (aka "classic") C++ world. However, it's a little too
> > coarse-grained, IMO. If you're dealing with types with
> > value semantics, then they're not likely to be in a
> > (well-written) runtime-polymorphic hierarchy. As such,
> > you're unlikely to be deleting them, if at all, via base
> > class pointers.
>
> Well that was my point ;-) Value types will not (generally)
> have virtual DTRs, so you shouldn't (generally) derive from them.
Well, I think the point I was making was that because value types
should not be dealt with polymorphically anyway, there's no reason
to *not* derive from them, except for the fact that it might incline
the unwary to start treating them polymorphically.
Personally, I'm quite happy with doing so via templates, but I still
get an uneasy feeling seeing it done in a non-template way. (Too much
exposure to clients' codebases containing classes deriving from
std::string
in order to provide an implicit conversion
operator a la
CString
. Groan ...)
> (And I don't know about "classic"; C++ has long been multi-paradigm)
Fair point. ;)
Maybe it's old farts like me that have spent so many years playing
around before templates were widely usable.
> But it's a good point, well made. The difference between Value and
> Polymorphic/Entity/... behaviour is often not stressed enough.
Agreed. (<blatant>My new book does make this distinction, and looks
a little deeply into the meaning of value types</blatant>)
> > I think this is especially the case in template-world.
> > It's very useful to be able to apply a compile-time
> > adaptation to (value) types, via templates that inherit
> > from their parameterising types.
>
> Yes. The "Curiously Recurring Template Pattern". The base classes are
> generally mixin types in this case, tho, and have no state, just behaviour.
While CRTP is most certainly an example of what I'm talking about, it's
more specialised. The idea I'm talking about is not necessarily recursive.
It looks like the following:
template <class T>
class X
: public T
{
. . . // blah blah
};
class SomeValueType
{
};
typedef X<SomeValueType> better_value_t;
In my book <sorry, I don't mean to be such a tool ;)> I discuss the concepts
of
Veneers and
Bolt-ins, which both follow this pattern. Veneers are the
things we're talking about here, for adapting/adorning value-types, since
they are not allowed to add non-static member variables, and must respect
the polymorphic nature of their primary parameterising type.
An example from the STLSoft libs is the mfcstl::cstring_veneer, which adapts
the old
CString
class into something with a
std::basic_string<>
-like interface,
i.e.
c_str()
, iterators, etc.
> > Again, such types are not
> > going to be deleted by pointers to base class, so there's
> > no need to encumber original class or composite with a
> > vtable.
>
> Agreed. My own practice is to make the DTR protected and non-virtual in the
> base, thus preventing any misuse.
Agreed. Herb's new book -
Exceptional C++ Style - talks about this specifically.
> > Naturally, it's open to abuse, but that's why I'm
> > stressing value types. It's most certainly the case that
> > this could be abused if applied to (runtime polymorphic)
> > entity types.
>
> When I say "Classes you intend to derive from" I mean "Polymorphic and/or
> Entity Types"; I should have made that clearer. By Entity Types I mean
> types generally used to indicate behavioural contract, like Interfaces.
Agreed.