Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Deriving from concrete types

1 view
Skip to first unread message

Holger Sebert

unread,
Jun 22, 2006, 6:59:28 AM6/22/06
to
Hi all,

I know that is in general a bad idea to derive from concrete types. However, I
wonder if it is o.k. if the derived class does not add any data members but only
extends the interface. For example:

class SpecialIntVector : public std::vector< int > {
public:
// ... int vector specific member functions go here ...
};

class SpecialFloatVector : public std::vector< float > {
public:
// ... float vector specific member functions go here ...
};

In this example, one automatically obtains STL-compatible vector types (except
for the constructors, of course) and has a syntactically clean extension of the
interface:

SpecialIntVector v;
v.resize( 1000 );
v.doSomethingSpecial();

Where are the problems with this approach?

Regards,
Holger

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Ulrich Eckhardt

unread,
Jun 23, 2006, 5:59:45 AM6/23/06
to
Holger Sebert wrote:
> I know that is in general a bad idea to derive from concrete types.

...because when you delete them via a pointer to the baseclass, the
destructor is not invoked polymorphically, leading to undefined behaviour.

> However, I wonder if it is o.k. if the derived class does not add any data
> members but only extends the interface.

Still undefined behaviour.

> SpecialIntVector v;
> v.resize( 1000 );
> v.doSomethingSpecial();
>
> Where are the problems with this approach?

As said above. If that doesn't apply, there is still another question left:
why? std::vector has no virtual functions you could overwrite and no
protected members you would get access to, so what's the gain?

I'd rather do this:

vector<float> v(1000);
DoSomethingSpecial(v);

..or even this:

vector<float> v(1000);
DoSomethingSpecial(v.begin(), v.end());

..or perhaps the equivalent using ranges.

Uli

Victor Bazarov

unread,
Jun 23, 2006, 6:02:04 AM6/23/06
to
Holger Sebert wrote:
> I know that is in general a bad idea to derive from concrete types.

Oh, you *know* that, don't you? As if it's true...

> However, I wonder if it is o.k. if the derived class does not add any
> data members but only extends the interface.

Only if it truly *extends* it.

Deriving from a concrete type if perfectly fine. People do it all the
time and live to talk about it. There are no language problems in it.
The problems are of the OOD kind.

> For example:
>
> class SpecialIntVector : public std::vector< int > {
> public:
> // ... int vector specific member functions go here ...

Like what?

> };
>
> class SpecialFloatVector : public std::vector< float > {
> public:
> // ... float vector specific member functions go here ...

Again, like what?

> };
>
> In this example, one automatically obtains STL-compatible vector
> types (except for the constructors, of course) and has a
> syntactically clean extension of the interface:
>
> SpecialIntVector v;
> v.resize( 1000 );
> v.doSomethingSpecial();

Special? Don't you mean, "SomethingEvenMoreGeneric"?

> Where are the problems with this approach?

You mean, besides that you don't really describe what kind of
"extension" you're talking about?

This has been discussed so many times (try reading archives of the
'comp.object' newsgroup), I don't want to beat the dead horse. One
of the most often given examples is "extending" a string to model
a phone number. Or, "extending" a rectangle to model a square
(because we know that a square "is-a" rectangle, don't we?)

Again, there is no C++ language problem when it comes to inheriting
from a concrete class. A better place to ask would be comp.object,
since with public inheritance you may be violating the basic OOD
principle of substitutability. Of course, *private inheritance* is
a totally different bag of kittens, and is a very well-known and
widely used idiom, called "implement in terms of" (and ont "is-a").

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

RenjithMohan

unread,
Jun 23, 2006, 6:07:36 AM6/23/06
to
Holger Sebert wrote:

> Hi all,
>
> I know that is in general a bad idea to derive from concrete types. However, I
> wonder if it is o.k. if the derived class does not add any data members but only
> extends the interface. For example:
>
> class SpecialIntVector : public std::vector< int > {
> public:
> // ... int vector specific member functions go here ...
> };
>
> class SpecialFloatVector : public std::vector< float > {
> public:
> // ... float vector specific member functions go here ...
> };
>
> In this example, one automatically obtains STL-compatible vector types (except
> for the constructors, of course) and has a syntactically clean extension of the
> interface:
>
> SpecialIntVector v;
> v.resize( 1000 );
> v.doSomethingSpecial();
>
> Where are the problems with this approach?
>
> Regards,
> Holger

This has been discussed umpteen times in this and other newsgroups.
I will summarize the points

1)Generally speaking the STL containers are not intended to be used as
base classes.
It is evident from the fact that they dont have a virtual destructor.
And you know what happens when you delete a base pointer if the
contained object is a derived one. It is Undefined Behaviour.
If you provide such a class nothing prevents from your clients to do
so.
2)They dont have any protected members or virtual functions to warrant
the design of public inheritance.
If you need to provide enhanced functionality it is prefered to provide
non member functions to achieve this, much like the algorithms

Holger Sebert

unread,
Jun 24, 2006, 5:34:55 AM6/24/06
to
Ulrich Eckhardt wrote:
> Holger Sebert wrote:
>
>>I know that is in general a bad idea to derive from concrete types.
>
>
> ...because when you delete them via a pointer to the baseclass, the
> destructor is not invoked polymorphically, leading to undefined behaviour.

Ooops ... I did not know that it is /undefined behaviour/. I have thought that
in such a case the destructor of the base class is invoked, which I thought was
o.k. because there are no additional data members in the derived class (in this
case).

> [...]


>
> I'd rather do this:
>
> vector<float> v(1000);
> DoSomethingSpecial(v);
>
> ..or even this:
>
> vector<float> v(1000);
> DoSomethingSpecial(v.begin(), v.end());
>
> ..or perhaps the equivalent using ranges.
>
> Uli
>

Well at least you would have something like a strong typedef in this case. This
is important if you have some operations which should only be applied to an,
e.g., SpecialFloatVector, and not an std::vector< float >. (I know of
boost::strong_typedef, but in my code I cannot use the boost libs).

Another point: Suppose you have a class X that must behave as a std::list<>, but
also has to have additional member functions (e.g. to provide an interface that
is consistent with other classes). How do you deal with that?

The only way I can think of is putting this std::list<> inside the class X as a
data member and write tons of delegate functions. But this becomes annoying
already if you have two or three of such cases ...

Regards,
Holger

Pete Becker

unread,
Jun 24, 2006, 5:31:58 AM6/24/06
to
RenjithMohan wrote:

>
> 1)Generally speaking the STL containers are not intended to be used as
> base classes.
> It is evident from the fact that they dont have a virtual destructor.

Non sequitur. What is evident from that fact is that you should not
delete an object of a derived type through a pointer to the base. There
are many uses of inheritance that do not require that sort of deletion.

> And you know what happens when you delete a base pointer if the
> contained object is a derived one. It is Undefined Behaviour.

That is, you don't know what happens.

> If you provide such a class nothing prevents from your clients to do
> so.

Nothing except their competence as programmers.

--

Pete Becker
Roundhouse Consulting, Ltd.

Alan McKenney

unread,
Jun 24, 2006, 5:37:02 AM6/24/06
to
RenjithMohan wrote:

<original post deleted>

> This has been discussed umpteen times in this and other newsgroups.
> I will summarize the points
>
> 1)Generally speaking the STL containers are not intended to be used as
> base classes.
> It is evident from the fact that they dont have a virtual destructor.
> And you know what happens when you delete a base pointer if the

> ... object is a derived one. It is Undefined Behaviour.

> If you provide such a class nothing prevents from your clients to do
> so.

Except the same thing that prevents your clients from dereferencing
a null or deleted pointer: your clients' desire not to have their
programs crash.

To what extent should we use a convoluted solution instead
of an elegant solution just because a stupid user can use
it to make his program crash?


> 2)They dont have any protected members or virtual functions to warrant
> the design of public inheritance.
> If you need to provide enhanced functionality it is prefered to provide
> non member functions to achieve this, much like the algorithms

This particular bit of dogma, like much of the
catechism of the C++ One True Way that gets
trotted out at every opportunity, depends upon some
assumptions about how C++ code will be used.
This bit of dogma assumes:

1. All C++ classes are created by all-knowing library
writers, who know best how the class may and
may not be used, while C++ classes are used
by clueless idiots who don't read documentation
and will start WWIII if we're not careful.

Now I grant you, this applies in a lot of cases
(which are well-represented in this newsgroup), but
in my experience, there are a lot of cases where
the user of the classes may know more than the
implementer, and where the ability to use a class
in ways that the author never intended is precisely
what makes the class useful.

2. The only reason for derivation is to allow
polymorphic use (treating a derived
class as a base class.)

If you need an object which acts just like a
std::vector, but you need a little extra functionality,
then deriving from std::vector is the *obvious* thing
to do.

That way, you get all the std::vector behavior "for
free", and you only need to add the extra member
function or two to get the desired extra
functionality.

Note that I didn't say: I'm working with a bunch
of vectors, but I want one of my vectors to act a little
different from std::vector. Instead, I need a Whatsit,
and what I need Whatsits to do turns out to be pretty
much what a std::vector does, plus some stuff.

So we're not talking about polymorphic use, and
there's no reason to pass around with pointers
to std::vector , unless you're entering an obfuscated
C++ contest.


On another note: some posters have indicated that
one should use "private" inheritance.

Now, I've never used private inheritance, but it
seems to me that if you derive privately from std::vector,
then all the std::vector functions are inaccessible
to the user of the class, which sort of defeats the
purpose.

Free functions are doable, but then you have
issues of possible name clashes, and you can't
use the member function syntax.

-- Alan McKenney

w...@seed.net.tw

unread,
Jun 25, 2006, 9:55:17 AM6/25/06
to
Holger Sebert 寋�:

> Hi all,
>
> I know that is in general a bad idea to derive from concrete types. However, I
> wonder if it is o.k. if the derived class does not add any data members but only
> extends the interface. For example:

> ..

If suitable, one can derive from any class. Polymorphical classes
are not without their drawbacks in derivation.

IJ. Wang

Bernhard Jungk

unread,
Jun 26, 2006, 4:49:01 AM6/26/06
to
> 2. The only reason for derivation is to allow
> polymorphic use (treating a derived
> class as a base class.)

This isn't a dogma of the C++ community. It's a matter of good
OOD. Public inheritance is provided to allow polymorphic use.
The derived class has to be replaceable with the base class.
If the base class isn't designed to be derivable, it shouldn't be
done with public inheritance.

Public inheritance defines a "is a" relationship and
therefore the client is able to use an instance of the derived class
like an instance of the base class. All contracts of the base class
must hold. (e.g. it must be guaranteed, that the derived object may
be destructed correctly through a base pointer.)

Private (and protected) inheritance defines a "is implemented
in terms of" relationship. Which is similar to a composition, which
should be preferred over private inheritance, if possible.

> Now, I've never used private inheritance, but it
> seems to me that if you derive privately from std::vector,
> then all the std::vector functions are inaccessible
> to the user of the class, which sort of defeats the
> purpose.

You can make the members publicly accessible again with a using
directive.

- Bernhard -

Kirit Sælensminde

unread,
Jun 26, 2006, 4:49:32 AM6/26/06
to

Alan McKenney wrote:
> On another note: some posters have indicated that
> one should use "private" inheritance.
>
> Now, I've never used private inheritance, but it
> seems to me that if you derive privately from std::vector,
> then all the std::vector functions are inaccessible
> to the user of the class, which sort of defeats the
> purpose.

Read up on the 'using' syntax.

class MyVector : private std::vector< int > {
public:
using operator [];
using resize;
// etc.
};

Now you can control exactly the members that you wish to include and
you cannot use a MyVector as a substitute for any std::vector< int >
either.


Kirit

Seungbeom Kim

unread,
Jun 27, 2006, 7:09:07 AM6/27/06
to
Bernhard Jungk wrote:
>> 2. The only reason for derivation is to allow
>> polymorphic use (treating a derived
>> class as a base class.)
>
> This isn't a dogma of the C++ community. It's a matter of good
> OOD. Public inheritance is provided to allow polymorphic use.
> The derived class has to be replaceable with the base class.
> If the base class isn't designed to be derivable, it shouldn't be
> done with public inheritance.
>
> Public inheritance defines a "is a" relationship and
> therefore the client is able to use an instance of the derived class
> like an instance of the base class. All contracts of the base class
> must hold. (e.g. it must be guaranteed, that the derived object may
> be destructed correctly through a base pointer.)

What you said is true indeed, but what do you think of the following?

template <class Arg, class Result>
struct unary_function {
typedef Arg argument_type;
typedef Result result_type;
/* no virtual destructor */
};

template <class T>
struct negate : /* public inheritance */ unary_function<T,T> {
T operator()(const T& x) const;
};

Even the standard library does have an exception; where it does not
guarantee that a derived object may be destroyed correctly through a
base pointer.

We assume that nobody will try to delete a negate object through a
unary_function pointer. What can be said if a similar assumption can
be made for a user-defined class?

--
Seungbeom Kim

kanze

unread,
Jun 27, 2006, 7:23:20 AM6/27/06
to
Bernhard Jungk wrote:
> > 2. The only reason for derivation is to allow
> > polymorphic use (treating a derived
> > class as a base class.)

> This isn't a dogma of the C++ community. It's a matter of good
> OOD. Public inheritance is provided to allow polymorphic use.
> The derived class has to be replaceable with the base class.

That depends. I think your confusing derivation and
inheritance. Or whatever you want to call them; the confusion
often occurs, because there is no standard vocabulary for
distinguishing between:

-- an essential OO design pattern, in which a number of derived
types can be used indifferently in place of the base type,
and

-- a C++ implementation technique, which is often used to
implement the design pattern, but of course, can be used to
implement other patterns as well.

If you are using C++ inheritance to implement OO derivation (or
is it C++ derivation to implement OO inheritance---as I said,
there is no established vocabulary for making the distinction),
then the base class very definitly must be designed
intentionally to be a base class for OO derivation. Which
includes such things as having a virtual destructor. And which
std::vector is not. If you are using C++ inheritance for some
other reason, the other rules may apply; std::iterator is
certainly designed to be a base class in the C++ sense, even if
it has no virtual functions.

My experience has been that users tend to be able to cope with
this pretty well, as long as you've documented the role your
class was designed to fulfil. I've never heard of anyone trying
to delete an iterator through an std::iterator*, for example.
(For that matter, I don't think I've ever heard of anyone even
declaring an std::iterator*.)

> If the base class isn't designed to be derivable, it shouldn't
> be done with public inheritance.

You see. You've mixed the two. Inheritance is a C++
implementation technique; derivation is a design concept. If
the reason you are using inheritance is to implement derivation,
then you should ensure that your class is designed with
derivation in mind. If you are using it for some other reason,
you should ensure that your class meets the requirements for
whatever the reason.

> Public inheritance defines a "is a" relationship

Public derivation defines a "is a" relationship. Public
inheritance is the obvious way to implement it. So much so that
I would say that public derivation implies public inheritance.
But it's not an if and only if relationship.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

todma

unread,
Jun 27, 2006, 7:36:51 AM6/27/06
to
> Read up on the 'using' syntax.
>
> class MyVector : private std::vector< int > {
> public:
> using operator [];
> using resize;
> // etc.
> };
>
> Now you can control exactly the members that you wish to include and
> you cannot use a MyVector as a substitute for any std::vector< int >
> either.
>
>
> Kirit
Was 'using' created mainly to solve this problem? I guess this is a
motivation to upgrade my compiler.
Was the small debate here over deriving from a class without virtual
destructors a classic debate that is now resolved via the 'using'
keyword?
This relates to my desire to derive classes from vector<> and pair<>.
Is this desire in fact misguided?
thanks,
Todd.

Alan McKenney

unread,
Jun 27, 2006, 7:33:56 AM6/27/06
to

Kirit Sælensminde wrote:
> Alan McKenney wrote:
> > On another note: some posters have indicated that
> > one should use "private" inheritance.
> >
> > Now, I've never used private inheritance, but it
> > seems to me that if you derive privately from std::vector,
> > then all the std::vector functions are inaccessible
> > to the user of the class, which sort of defeats the
> > purpose.
>
> Read up on the 'using' syntax.
>
> class MyVector : private std::vector< int > {
> public:
> using operator [];
> using resize;
> // etc.
> };
>
> Now you can control exactly the members that you wish to include and
> you cannot use a MyVector as a substitute for any std::vector< int >
> either.


True.

But if you want all the std::vector<> member functions, how is this
better than just using public inheritance?

A disadvantage of putting in "using" declarations for every
std::vector function is that it's an opportunity for errors and
omissions.


-- Alan McKenney
[line eater fodder]
[munch, munch]

Alan McKenney

unread,
Jun 27, 2006, 7:33:20 AM6/27/06
to
Bernhard Jungk wrote:
> > 2. The only reason for derivation is to allow
> > polymorphic use (treating a derived
> > class as a base class.)
>

> ... Public inheritance is provided to allow polymorphic use.

Perhaps in the OOD paradigm, this is the only reason for
public inheritance (I'm not an expert in OOD theory.)

However, one of C++'s strengths is that it supports
multiple paradigms. And one real non-OOD use of
derivation is code re-use, where there is no expectation
of polymorphic use.

The OP's example is, to my mind, a perfect example
of derivation for code re-use: a new class which is
similar to an existing class.

By using public inheritance, the new class definition
contains only those things which distinguish it from
the existing class, thus making it clear to anyone
who reads it what is going on.

(Yes, you can use private inheritance, but then
you have to put in a "using" declaration for every
base class function and operator. Quick, how
many of you can rattle off all the member functions
and operators in std::vector without looking at
the documentation?)

If Stroustrup had intended to create a language
which would force people to fit their code into
OOD paradigms, perhaps he would have made
it impossible to derive from a class with a non-virtual
destructor. Or made it impossible to override
non-virtual functions.

Fortunately, he did not.

And C++ is all the more useful for it.

(Just think of all the one-paradigm languages out there --
have *any* of them become more than niche languages?)

-- Alan McKenney

Kirit Sælensminde

unread,
Jun 28, 2006, 6:29:11 AM6/28/06
to

Alan McKenney wrote:
> Kirit Sælensminde wrote:
> > Alan McKenney wrote:
> > > On another note: some posters have indicated that
> > > one should use "private" inheritance.
> > >
> > > Now, I've never used private inheritance, but it
> > > seems to me that if you derive privately from std::vector,
> > > then all the std::vector functions are inaccessible
> > > to the user of the class, which sort of defeats the
> > > purpose.
> >
> > Read up on the 'using' syntax.
> >
> > class MyVector : private std::vector< int > {
> > public:
> > using operator [];
> > using resize;
> > // etc.
> > };
> >
> > Now you can control exactly the members that you wish to include and
> > you cannot use a MyVector as a substitute for any std::vector< int >
> > either.
>
>
> True.
>
> But if you want all the std::vector<> member functions, how is this
> better than just using public inheritance?

There are three things here:
* OO inclusional polymorphism - that a sub-class can be substituted for
a super-class. Where we pass pointers & references and use virtual
functions.
* Operational polymorphism - where we define the interface. As used by
templates.
* Convenience - where a class does most of what we want, but we want to
change it a litle.

Deriving from std::vector for the first reason is misguided at best, a
severe bug at worst. You may be lucky in exactly what you're doing...
but...

For the other two reasons you should be thinking about which members of
std::vector you are using and how you are using them. You may not want
all of them and they may not all be relevant.

In any case you *do* want to stop your derived class being used for
inclusional polymorphism and deriving privately neatly does that.

> A disadvantage of putting in "using" declarations for every
> std::vector function is that it's an opportunity for errors and
> omissions.
>

It is inconvenient for the person defining the class, but means that it
cannot be misused later. If you believe that the contract of intent of
the software is described in the source then you should make the point
that your class is *not* a substitute for the super-class explicit in
the code. The C++ compiler is generally more effective at enforcing
design trade-offs then external documentation.


Kirit

Andrei Alexandrescu (See Website For Email)

unread,
Jun 28, 2006, 6:37:41 AM6/28/06
to
Alan McKenney wrote:
> However, one of C++'s strengths is that it supports
> multiple paradigms. And one real non-OOD use of
> derivation is code re-use, where there is no expectation
> of polymorphic use.
>
> The OP's example is, to my mind, a perfect example
> of derivation for code re-use: a new class which is
> similar to an existing class.

I disagree. It's more like the perfect example of a misapplication of a
feature. I'm surprised nobody mentioned the problems of this approach.

If somebody wants a new class that is similar to an existing class, they
simply add functions taking an object of that class as an argument. That
way, all code that *already* manipulates objects of the existing class
has presto access to the newly-defined functionality without any change
to the existing code - no changes of local variables' types, no changes
to members' types, no changes to function signatures. This is the
baseline against which you want to compare the public inheritance approach.

Now: If, on the other hand, somebody defines cool_vector<T> to inherit
vector<T>, they'll face two problems. One is that, in order to banefit
of the newly-added functionality, they'll have to change an unbounded
amount of the existing code. For example, if you had a function:

void Fun(const vector<T> & v);

now if you wanted Fun to use cool_vector<T>'s functionality, you need to
either (a) change the signature and the code around Foo's call sites,
(b) construct a cool_vector from the vector inside Foo, or (c) cast v to
cool_vector<T>&. The first option is impractical, the second
inefficient, and the third incorrect.

The second problem is that whatever extra invariants the derived class
would like to hold (either about the vector itself or between the vector
and whatever extra member variables cool_vector might hold), that won't
be possible. Vector<T> doesn't have any virtual functions, so anybody
extracting the vector<T> & from a cool_vector<T> can use it in any way a
vector<T> could be used.

With these considerations in mind, if you want to add new functionality
to an existing class, you add it as free functions if no add of state is
neededed, or via private inheritantce if you need to add state and
maintain some invariant involving the base class and the extra state. If
you just want to add unsynchronized state, make that a separate class or
use pair.

Public inheritance for symbol injection is usable in many template
programming scenarios, the simplest being std::*_function.

> By using public inheritance, the new class definition
> contains only those things which distinguish it from
> the existing class, thus making it clear to anyone
> who reads it what is going on.

I have no doubt reading the new class should be easy enough. But many
simple things have messy implications. In this case, they are: extensive
and gratuitous changes to existing code, and inability to maintain
invariants for the new class.

> (Yes, you can use private inheritance, but then
> you have to put in a "using" declaration for every
> base class function and operator.

Free functions are the baseline you may want to compare other approaches
against.


Andrei

Ulrich Eckhardt

unread,
Jun 28, 2006, 6:32:21 AM6/28/06
to
Alan McKenney wrote:
> Kirit Sælensminde wrote:
>> class MyVector : private std::vector< int > {
>> public:
>> using operator [];
>> using resize;
>> // etc.
>> };
>>
>> Now you can control exactly the members that you wish to include and
>> you cannot use a MyVector as a substitute for any std::vector< int >
>> either.
>
>
> True.
>
> But if you want all the std::vector<> member functions, how is this
> better than just using public inheritance?

The point is that now you have exact control. In particular, access to the
base-class' destructor is denied, which would lead to UB if it was used.

> A disadvantage of putting in "using" declarations for every
> std::vector function is that it's an opportunity for errors and
> omissions.

Omissions, yes, errors less so. The worst that can happen is a compiler
error because you forgot to allow access to a functions. In the case of
public inheritance, the worst that can happen is undefined behaviour. I
prefer compile-time errors by far.

Uli

Oleksandr Yefremov

unread,
Jun 28, 2006, 6:33:26 AM6/28/06
to
Take a look at following two classes:

template<class T>
class extended_vector : public vector<T>
{
public:
// our super duper function
void extendet_function();
};


template<class T>
class extended_vector2 : private vector<T>
{
public:
// multiple using declarations of vector interface
// using ...
// using ...

// our super duper function
void extendet_function();

// to be able use extended_vecotr2 where vector expected
operator vector<T>&() {return *this;}
operator const vector<T>&() const {return *this;}
};

In this example extended_vector and extended_vector2 will work in the
same way. Final user can delete both of them using base class pointer.
But second class is all OOD valid (or not?).

I can say only: Use all the power of C++, ignore OOD if it limit your
code. Code must be beautifull.

Oleksandr Yefremov

RenjithMohan

unread,
Jun 28, 2006, 6:40:30 AM6/28/06
to
Alan McKenney

> If Stroustrup had intended to create a language
> which would force people to fit their code into
> OOD paradigms, perhaps he would have made
> it impossible to derive from a class with a non-virtual
> destructor. Or made it impossible to override
> non-virtual functions.
>
> Fortunately, he did not.
>
> And C++ is all the more useful for it.
>
> (Just think of all the one-paradigm languages out there --
> have *any* of them become more than niche languages?)

As has been pointed out here, derivation if used in this way, leads to
tighter coupling and leads to a dependency cycle which is to say the
least non maintanable.
When high level modules depend on concrete types as they have to since
the functions you add to the interface has to specifically called, it
induces a bad form of abstraction.
This is the more important reason than the virtual dtor problem.
When you create new types you have a responsibility to fulfill. You are
also creating an interface into your realm of usefulness. The more
intutive the interface, the better.

OOD has evolved and reached a mature state now.
Here abstraction is the king. Concrete types are slaves.
I dont want to be too feudal in my imagery here, but high level people
can ill afford to depend on replaceable entities.

A future era may come where the language would help us to enforce
paradigms like this. I mean to say an era where public inheritance only
allows anything but pure LSP.

However there are noteworthy exceptions to this polymorphic bandwagon.
Consider the concept of veneers where by you slice a hirearchy and add
functionalities non intrusively.

template <typename T>
class CapVeneer : public T
{
typedef T ParentClass;
typedef CapVeneer<T> Class;

public:
int MyNewFunction();

];

whereby you have extended the type T by adding a new function.
please note that non template derivation would not do here as you would
have to create a class for each such type in the hierarchy while with
the CRTP, you avoid repeatation and can instantiate things in a nice
way, wherever you require T you can use CapVeneer<T> instead (or a
typedef) and also get the new added function MyNewFunction for that T..
I dont know whether from a library perspective, veneers are as bad as
deriving from concrete types.

Carl Barron

unread,
Jun 28, 2006, 6:42:10 AM6/28/06
to
In article <1151354600.5...@r2g2000cwb.googlegroups.com>,
todma <toddmars...@yahoo.com> wrote:

> > Read up on the 'using' syntax.
> >
> > class MyVector : private std::vector< int > {
> > public:
> > using operator [];
> > using resize;
> > // etc.
> > };
> >
> > Now you can control exactly the members that you wish to include and
> > you cannot use a MyVector as a substitute for any std::vector< int >
> > either.
> >
> >
> > Kirit
> Was 'using' created mainly to solve this problem? I guess this is a
> motivation to upgrade my compiler.
> Was the small debate here over deriving from a class without virtual
> destructors a classic debate that is now resolved via the 'using'
> keyword?
> This relates to my desire to derive classes from vector<> and pair<>.
> Is this desire in fact misguided?
> thanks,
> Todd.
>

The facts are these according to the standard [approved and 06 draft]
but I quote 06 draft since I can copy and paste from it..
Section 11.2 paragraph 1 of N2009=06-0079 dated 2006-04-21 states:
<quote>
If a class is declared to be a base class (clause 10) for another class
using the public access specifier, the public
members of the base class are accessible as public members of the
derived class and protected members of the base
class are accessible as protected members of the derived class. If a
class is declared to be a base class for another
class using the protected access specifier, the public and protected
members of the base class are accessible as
protected members of the derived class. If a class is declared to be a
base class for another class using the private
access specifier, the public and protected members of the base class
are accessible as private members of the
derived class.
</quote>.
related footnote
<quote>
As specified previously in clause 11, private members of a base class
remain inaccessible even to derived classes unless friend declarations
within the base class definition are used to grant access explicitly.
</quote>
Therefore C++ inheritance is a superset of OOD inheritance/derivation.
Any other definition such as its an 'x a' relatiionship is a speial
case if the above descriptions hold. Deriving from a concrete class is

a legal reuse of code. See <stack> note the container used for the
stack is a PROTECTED member. so that special stacks can be written
without rewriting the entire std::stack class as something else.

If you are generally assuming C++ inheritance -> OOD inheritance you
are mistaken. OOD inheritance is included in C++'s public inheritance,
and is often the most often used use of public inheritance, but not the
only one. If you use C++ public inheritance, I do recommend you
document this is not an OOD inheritance, as unfortunately there is a
large number of programmers that assume, in error , that C++ public
inheritances is OOD inheritance.

To answer your question there is nothing wrong with deriving from
std::vector<T,A> as long as it is not used as an OOD inheritance. The
following is a stack, that allows random access read/write access to a
stack [not removal except the top].

struct my_stack:public std::stack<int,std::vector<int> >
{
int & operator [] (int n) { return c.operator [] (n);}
int & operator [] (int n) const {return c.operator[](n);}
};

Gene Bushuyev

unread,
Jun 29, 2006, 4:40:27 AM6/29/06
to
"kanze" <ka...@gabi-soft.fr> wrote in message
news:1151320889....@b68g2000cwa.googlegroups.com...
> Bernhard Jungk wrote:
[...]

>> If the base class isn't designed to be derivable, it shouldn't
>> be done with public inheritance.
>
> You see. You've mixed the two. Inheritance is a C++
> implementation technique; derivation is a design concept. If
> the reason you are using inheritance is to implement derivation,
> then you should ensure that your class is designed with
> derivation in mind. If you are using it for some other reason,
> you should ensure that your class meets the requirements for
> whatever the reason.
>
>> Public inheritance defines a "is a" relationship
>
> Public derivation defines a "is a" relationship.

It may or may not be. I don't favor making subtle distinctions about inheritance
and derivation, both are used interchangeably to refer to the mechanism of
creating subtypes in C++.
Going back to the classic work of Barbara Liskov, where she defined the
substitution principle:
"What is wanted here is something like the following substitution property: If
for each object o1 of type S there is an object o2 of type T such that for all
programs P defined in terms of T, the behavior of P is unchanged when o1 is
substituted for o2 then S is a subtype of T."

That pretty much restricts derivation to virtual functions, - the only way the
derived class can both extend the base and be reused in place of base class
without modifications of the existing code. Non-virtual inheritance, whether
public, private or protected, doesn't satisfy the substitution principle, it is
simply a way to reuse the base class in the derived. Such reuse comes with
inheritance member fees, such as interface pollution/collision and tight
coupling (second only to "friend") and possibility of errors (UB, slicing) if
substitution is erroneously attempted. This reuse can be achieved by
composition, which doesn't have any of those problems, except it requires
additional typing, which is never a good argument against doing design
correctly. Of course, there are plenty of simple cases in template designs of
value classes where the public derivation is an acceptable solution or the only
solution (e.g. CRTP), with little dangers of something going wrong. Still I
would do that only when necessary. Inheriting from a large concrete class like
std::vector is a gratuitous violation of design rules, which has only problems
and no real advantages.

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
To see what is in front of one's nose needs a constant struggle ~ George Orwell

Andrei Alexandrescu (See Website For Email)

unread,
Jun 29, 2006, 7:24:41 AM6/29/06
to
Kirit Sælensminde wrote:
> There are three things here:
> * OO inclusional polymorphism - that a sub-class can be substituted for
> a super-class. Where we pass pointers & references and use virtual
> functions.
> * Operational polymorphism - where we define the interface. As used by
> templates.
> * Convenience - where a class does most of what we want, but we want to
> change it a litle.

That's a nice terse characterization. Dwelling a bit on the first bullet
point, I was surprised at a point to realize that true polymorphism
"restricts" through inheritance; it does not "extend" at all. Java
pushed the confusion further by making "extends" a keyword. This way,
many beginners and even advanced programmers (as I thought I was when I
realized the mistake of my thinking) sdtrongly believe that the OOP way
is, you start with a "little" class and you "extend" it by adding
variables and functions.

In reality, true dynamic polymorphism is inclusion polymorphism: a base
class stands in as the most general concept, that _includes_ all of the
possible concepts inheriting it. From a member variables perspective,
the base class represents anything that has those members _and more_.
Therefore, as soon as you inherit a base and add your own member
variables, you actually restrict the generality of the base class, not
extend it.

So a Circle does not "extend" a Shape because the Shape is a more
general concept. It "particularizes" it. Same about ColoredPoint versus
Point. This is because Point represents a point that may be colored or
not, while ColoredPoint is just a subset of that set - a point that's
definitely colored.

These details are not directly related to the OP's question, but I
thought it's a nice opportunity to mention the set relationship modeled
in C++ by public inheritance.


Andrei

Francis Glassborow

unread,
Jun 29, 2006, 10:31:45 AM6/29/06
to
In article <1151341397.4...@c74g2000cwc.googlegroups.com>, Alan
McKenney <alan_mc...@yahoo.com> writes

> True.
>
> But if you want all the std::vector<> member functions, how is this
> better than just using public inheritance?
>
> A disadvantage of putting in "using" declarations for every
> std::vector function is that it's an opportunity for errors and
> omissions.
It is also an opportunity to consider what you actually need even if
that takes some time. One problem with public derivation is shown by:

#include "my_derived_vector.h"
std::vector<int> & foo(std::vector<int> );

int main(){
my_derived_vector<int> test;
my_derived_vector<int> & = foo(test);
// note foo treats test as a std::vector<int> in addition to the
return
problem
};

That just touches the edge of the coding problems once you start
publicly inheriting from standard containers.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/
youcandoit/projects

Francis Glassborow

unread,
Jun 29, 2006, 10:31:15 AM6/29/06
to
In article <1151320889....@b68g2000cwa.googlegroups.com>, kanze
<ka...@gabi-soft.fr> writes

> Public derivation defines a "is a" relationship. Public
> inheritance is the obvious way to implement it. So much so that
> I would say that public derivation implies public inheritance.
> But it's not an if and only if relationship.

And IMO, one of the strengths of C++ is that it provides alternative
forms of inheritance to deal with cases where inheritance is not OO
derivation. Unfortunately in the early days this was not used very much
perhaps because other languages supporting OO had no way to distinguish
(and generally containment was a better option)

In C++ we have a range of tools and serious practitioners need to learn
to choose the right tool for the job.

One problem in the early days was that most came from C where terse code
was the norm and were reluctant to spend more time coding 'correctly'.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/
youcandoit/projects

kanze

unread,
Jun 30, 2006, 7:55:24 AM6/30/06
to
Andrei Alexandrescu (See Website For Email) wrote:

> If somebody wants a new class that is similar to an existing
> class, they simply add functions taking an object of that
> class as an argument.

That's not always possible in C++. The language requires
certain functions to be members; in the case of std::vector, for
example, you can't add new constructors or a new operator[] that
way.

[For the rest, I pretty much agree with what you are saying.]

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

kanze

unread,
Jun 30, 2006, 7:56:00 AM6/30/06
to
Gene Bushuyev wrote:
> "kanze" <ka...@gabi-soft.fr> wrote in message
> news:1151320889....@b68g2000cwa.googlegroups.com...
> > Bernhard Jungk wrote:
> [...]
> >> If the base class isn't designed to be derivable, it shouldn't
> >> be done with public inheritance.

> > You see. You've mixed the two. Inheritance is a C++
> > implementation technique; derivation is a design concept. If
> > the reason you are using inheritance is to implement derivation,
> > then you should ensure that your class is designed with
> > derivation in mind. If you are using it for some other reason,
> > you should ensure that your class meets the requirements for
> > whatever the reason.

> >> Public inheritance defines a "is a" relationship

> > Public derivation defines a "is a" relationship.

> It may or may not be. I don't favor making subtle distinctions
> about inheritance and derivation, both are used
> interchangeably to refer to the mechanism of creating subtypes
> in C++.

The problem is that the two words are used interchangeably. Or
more strictly speaking, the problem is that we don't distiguish
through vocabulary two significantly different things: a design
concept and a C++ language structure. Now, it's true that the
C++ language structure was originally conceived to implement the
design concept (I think, anyway). But it remains a language
structure, and in modern C++, it is often used for other things.

Trying to force all uses of the language structure to conform to
rules which only apply to the design concept is, IMHO, an error.

> Going back to the classic work of Barbara Liskov, where she
> defined the substitution principle:

> "What is wanted here is something like the following
> substitution property: If for each object o1 of type S there
> is an object o2 of type T such that for all programs P defined
> in terms of T, the behavior of P is unchanged when o1 is
> substituted for o2 then S is a subtype of T."

No problem with that, but she is talking about the design
concept here.

> That pretty much restricts derivation to virtual functions,

If you don't have virtual functions, it is pretty clear that you
are not using C++ derivation to implement the design concept of
inheritance, but for some other reason.

For the rest, you seem to be making the same mistake I'm arguing
against: confusing the language structure used to implement it
with the design concept. WHEN derivation is used to implement
the OO design concept of inheritance, then it is clear that the
base class must have virtual functions, etc. When derivation is
used for other reasons (e.g. as when deriving from
std::iterator<...>), then other rules apply.

[...]


> Inheriting from a large concrete class like std::vector is a
> gratuitous violation of design rules, which has only problems
> and no real advantages.

I agree here. While I think that there are many reasons to use
C++ derivation, and not just to implement the OO design concept
of inheritance, none of them can be just randomly applied. A
class must be designed to be a base class, regardless of the
reasons why it is to be used as a base class. There is no
doubt, for example, that std::iterator<> was designed to be used
as a base class, although there is no doubt in my mind that this
use of C++ derivation does not correspond to the OO design
concept of inheritance. There is also no doubt in my mind that
std::vector<> was not so designed, and that any use of it as a
public base class will run into problems. Not because it
doesn't conform to the rules of the OO design concept, per se,
but because it doesn't conform to the rules of any design
concept which would normally be implemented using it as a base
class in C++.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Bo Persson

unread,
Jun 30, 2006, 7:51:10 AM6/30/06
to

"Gene Bushuyev" <sp...@spamguard.com> skrev i meddelandet
news:1%pog.161347$F_3....@newssvr29.news.prodigy.net...

But we are not always interested in polymorphic use of the classes.
There is no substitution invoved!

Try this snipet from the standard library:

template<class _ArgT, class _ResultT>
struct unary_function
{
typedef _ArgT argument_type;
typedef _ResultT result_type;
};

template<class _NumT>
struct plus : binary_function<_NumT, _NumT, _NumT>
{
_NumT operator()(const _NumT& _Left, const _NumT& _Right) const
{ return _Left + _Right; }
};


These classes are never dynamically allocated, never accessed trough a
pointer, and never ever assigned to a base class. No slicing, no
delete through pointer to base. Never!

Why do you believe that I cannot use similar hierarchies in my code?

Liskov has nothing to do with this!

>
> That pretty much restricts derivation to virtual functions, - the
> only way the
> derived class can both extend the base and be reused in place of
> base class
> without modifications of the existing code. Non-virtual inheritance,
> whether
> public, private or protected, doesn't satisfy the substitution
> principle, it is
> simply a way to reuse the base class in the derived. Such reuse
> comes with
> inheritance member fees, such as interface pollution/collision and
> tight
> coupling (second only to "friend") and possibility of errors (UB,
> slicing) if
> substitution is erroneously attempted.

What if substitution is not attempted? How could I assign an apple to
a fruit, when there are no fruit variables in the program?

> This reuse can be achieved by
> composition, which doesn't have any of those problems, except it
> requires
> additional typing, which is never a good argument against doing
> design
> correctly. Of course, there are plenty of simple cases in template
> designs of
> value classes where the public derivation is an acceptable solution
> or the only
> solution (e.g. CRTP), with little dangers of something going wrong.
> Still I
> would do that only when necessary.

And who decides when it is necessary? :-)


> Inheriting from a large concrete class like
> std::vector is a gratuitous violation of design rules, which has
> only problems
> and no real advantages.

True.


Bo Persson

Kirit Sælensminde

unread,
Jun 30, 2006, 7:50:39 AM6/30/06
to

Gene Bushuyev wrote:
> Going back to the classic work of Barbara Liskov, where she defined the
> substitution principle:
> "What is wanted here is something like the following substitution property: If
> for each object o1 of type S there is an object o2 of type T such that for all
> programs P defined in terms of T, the behavior of P is unchanged when o1 is
> substituted for o2 then S is a subtype of T."

The kind of polymorphism that you're discussing I've always called
'inclusional polymorphism', meaning that a type S 'includes' the type T
(using Liskov's terms).

What Liskov describes though sounds tighter as she specifies that the
behaviour of P is unchanged. It seems to me that a reasonable
interpretation of 'unchanged behaviour' would not include the
difference in bahaviour wrought by overriden virtual methods.

What it does cover though is the sort of substitution that you get when
you use a 'long' for an 'int', i.e. 'operational polymorphism' where
you expect different types to provide the same operations with the same
results. This is what you get with templated functions (the program P),
like std::min().

I've come across 'Liskov substitution' as a term a few times, but I've
not come across a good definition of it with examples of how the term
should be applied.

Can you shed some further light on it?


K

Ulrich Eckhardt

unread,
Jun 30, 2006, 8:03:23 AM6/30/06
to
Oleksandr Yefremov wrote:
> template<class T>
> class extended_vector : public vector<T>
> {
> public:
> // our super duper function
> void extendet_function();
> };
>
>
> template<class T>
> class extended_vector2 : private vector<T>
> {
> public:
> // multiple using declarations of vector interface
> // using ...
> // using ...
>
> // our super duper function
> void extendet_function();
>
> // to be able use extended_vecotr2 where vector expected
> operator vector<T>&() {return *this;}
> operator const vector<T>&() const {return *this;}
> };
>
> In this example extended_vector and extended_vector2 will work in the
> same way. Final user can delete both of them using base class pointer.

No. When the user creates an object of the first, deleting via a pointer to
the baseclass yields UB. With the second, the case is slightly different,
because they first need to invoke the user-defined conversion operator. If
it was a real memberfunction like get_base() I would say that this
implicitly tells the user that they are not supposed to delete it (like you
would never do when you got a reference from a functioncall) but even these
user-defined operators require rather malicious code in order to extract a
pointer to baseclass and then to delete it.

Anyhow, I don't think that direct access to the baseclass is intended,
because all functions that should be accessible (and the destructor is
simply not one of them) are made available via using declarations.

> ignore OOD if it limit your code.

Yes, OOD/OOP is only a tool. If it doesn't fit your problem, don't use it.

Uli

todma

unread,
Jun 30, 2006, 5:24:20 PM6/30/06
to
clarify???
so one person says:

..."Inheriting from a large concrete class like


std::vector is a gratuitous violation of design rules, which has only
problems

and no real advantages. "...


and just before that someone else says:
..."To answer your question there is nothing wrong with deriving from
std::vector<T,A> as long as it is not used as an OOD inheritance."...

Since the compiler allows it supposedly, how can i disallow OOD
inheritance when I want to use it?

Also, this seems like a natural thing for programmers to want or need
to do.... the OOD restriction seems unnatural unless there's a facility
for it specifically on or off. If someone does it then it can't be
mis-used, is that what's needed?

But wait, do vector<> etc. have any virtual functions? if not then they
can be derived from, they don't need virtual destructors, and can't be
destroyed through pointers to base classes, right?

Todd.

Markus Schoder

unread,
Jun 30, 2006, 9:17:31 PM6/30/06
to
Gene Bushuyev wrote:
> > Going back to the classic work of Barbara Liskov, where she defined the
> > substitution principle:
> > "What is wanted here is something like the following substitution
> > property: If for each object o1 of type S there is an object o2 of
type T
> > such that for all programs P defined in terms of T, the behavior of
P is
> > unchanged when o1 is substituted for o2 then S is a subtype of T."
> >
> > That pretty much restricts derivation to virtual functions, - the
only way
> > the derived class can both extend the base and be reused in place
of base
> > class without modifications of the existing code. Non-virtual
inheritance,
> > whether public, private or protected, doesn't satisfy the substitution
> > principle, it is simply a way to reuse the base class in the derived.

This is a non-sequitur.

If you non-trivially override virtual functions in a derived class it will
not be a subtype (in general) according to the above definition since in
terms of program behavior derived class objects will differ form base class
objects.

Gene Bushuyev

unread,
Jul 1, 2006, 5:45:44 AM7/1/06
to
"Bo Persson" <b...@gmb.dk> wrote in message
news:4ghmemF...@individual.net...

>
> "Gene Bushuyev" <sp...@spamguard.com> skrev i meddelandet
[...]

>> creating subtypes in C++.
>> Going back to the classic work of Barbara Liskov, where she defined
>> the
>> substitution principle:
>> "What is wanted here is something like the following substitution
>> property: If
>> for each object o1 of type S there is an object o2 of type T such
>> that for all
>> programs P defined in terms of T, the behavior of P is unchanged
>> when o1 is
>> substituted for o2 then S is a subtype of T."
>
> But we are not always interested in polymorphic use of the classes.
> There is no substitution invoved!

It's like saying: I created a boobytrapped door in my design, don't you dare
ever opening it. What's the point of public derivation if no substitution is
planned? If you are not overriding virtual functions in the base class, you're
not extending the base class, you're reusing it. If you wanted to extend a
concrete class, you would create non-member functions. If you wanted to reuse a
concrete class, you could use composition. As I pointed in my previous post, the
real excuse for derivational reuse is laziness.

>
> Try this snipet from the standard library:
>
> template<class _ArgT, class _ResultT>
> struct unary_function

I already contended in my previous post, that simple convience template classes,
that have little chances to be abused, and some template patterns are exempted.
It's a reasonable exception from the rule.

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
To see what is in front of one's nose needs a constant struggle ~ George Orwell

Alan McKenney

unread,
Jul 1, 2006, 5:47:25 AM7/1/06
to
kanze wrote:
> Gene Bushuyev wrote:

<snip>

> > Inheriting from a large concrete class like std::vector is a
> > gratuitous violation of design rules, which has only problems
> > and no real advantages.
>

> ... There is also no doubt in my mind that


> std::vector<> was not so designed, and that any use of it as a
> public base class will run into problems. Not because it
> doesn't conform to the rules of the OO design concept, per se,
> but because it doesn't conform to the rules of any design
> concept which would normally be implemented using it as a base
> class in C++.


It's funny. When I first added my $0.02 to this discussion,
I didn't have a concrete example. I was merely responding
to what I saw as overly rigid dogma.

However, just in the last hour, I find myself writing a class
which is publicly derived from std::vector .

The situation is that I have a class to implement a configuration
table. The (private) member object that holds the table data was
originally

typedef std::vector<Entry> KeywordData
std::vector<KeywordData> tableData;

(If anyone cares, Entry is basically a bag of data.)

Another part of the class maps the keyword to the index in
"tableData".

Writing the code to set up and to access the data went
quickly, because I (and anyone who maintains the code)
know all about how to use std::vector<> (well, almost all....)

I then went to write my "print()" function, which prints out
the contents of the table for debugging purposes,
(one of my design principles: never create a complicated
data structure without a "print()" function!) and
realized that "tableData" didn't have the keyword.

At first, in line with the suggestions in this thread, I tried
making KeywordData a class:

struct KeywordData { std::vector<Entry> data; std::string keyword; };

but since I wanted to preserve the interface, I found myself
writing forwarding functions for large parts of the std::vector
interface, with frequent trips to the std::vector man page to
get all the types just right.

This violated my personal design principle of not
reimplementing the wheel.

I then tried using private inheritance, but found myself
cut-and-pasting and "awk"ing from Sun's man pages
to get the many, many "using" statements.

This violated my design principle of avoiding
cut-and-paste. (Anyone who has had to maintain
code with large amounts of cut-and-pasted code will
understand this.)


I then thought of moving "keyword" to a separate vector,
but this violated my design principle of keeping related
data together. (20 years of Fortran programming really
soured me on emulating structs by using parallel data
structures.)


So, in accordance with *my* design principles, developed
over 30 years of large-scale software development and
maintenance, led me to do:

struct KeywordData : public std::vector<Entry> { std::string keyword;
};
std::vector<KeywordData> tableData;

So far, given how I use the class, I don't see a problem.

It's quick to write, economical in concepts, requires no change
to the part of the code that expected a std::vector, the meaning
is obvious to anyone who reads the code, and the "gotchas"
are obvious, at least to anyone who reads this newsgroup :-)

And, short of spending a few days (which I can't afford) coming
up with a different design that satisfies the OOD crowd, I don't
see a better, more obvious design.

-- Alan McKenney

Gene Bushuyev

unread,
Jul 1, 2006, 5:46:04 AM7/1/06
to
"kanze" <ka...@gabi-soft.fr> wrote in message
news:1151579722.5...@b68g2000cwa.googlegroups.com...
> Gene Bushuyev wrote:
[...]

>> That pretty much restricts derivation to virtual functions,
>
> If you don't have virtual functions, it is pretty clear that you
> are not using C++ derivation to implement the design concept of
> inheritance, but for some other reason.

What are those other reasons?
I'm repeating myself, but since nobody addressed it, I do it again. Public
inheritance can be used for two purposes: to extend the base class overriding
virtual functions (substitution principle), or to reuse the base class in
derived. The later can be justified in some template patterns, but not in
general case.

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
To see what is in front of one's nose needs a constant struggle ~ George Orwell

Carl Barron

unread,
Jul 1, 2006, 2:00:03 PM7/1/06
to
todma <toddmars...@yahoo.com> wrote:

> clarify???
> so one person says:
>
> ..."Inheriting from a large concrete class like
> std::vector is a gratuitous violation of design rules, which has only
> problems
> and no real advantages. "...
>
>
> and just before that someone else says:
> ..."To answer your question there is nothing wrong with deriving from
> std::vector<T,A> as long as it is not used as an OOD inheritance."...
>
> Since the compiler allows it supposedly, how can i disallow OOD
> inheritance when I want to use it?
>

He probably means that is not used where theere is an attempt to
delete a Derived * using a Base * [see DontDo This below as a BAD
EXAMPLE]
I like the C/C++ principle 'Just because you can commit suicide with
this doesn't make it illegal' :)
There is no general method to strictly enforece this with a compiler
seeing only part of the total source code at a time.
If your class is to be used as a library component Document it is not
classical OOP. If the user drives off a bridge that is out and it is
clearly marked, its not your fault....

> Also, this seems like a natural thing for programmers to want or need
> to do.... the OOD restriction seems unnatural unless there's a facility
> for it specifically on or off. If someone does it then it can't be
> mis-used, is that what's needed?
>
> But wait, do vector<> etc. have any virtual functions? if not then they
> can be derived from, they don't need virtual destructors, and can't be
> destroyed through pointers to base classes, right?
>
> Todd.
>

void foo(std::vector<int> *p) {delete p;}

class DontDoThis:public std::vector<int>
{
double *foo;
public:
DontDoThis():foo(new double[500]){}
~DontDoThis() {delete [] foo;}
];

int main
{
DontDoThis p(new DontDoThis);
foo(p);
}

should produce a memory leak [DontDoThis's dtor not called]
That is the type of problem that all thees inheritance only for OOD
crowd is complaining about. not deleteing a base class of vector. The
standard provide none but if it has any base classes they are
implementation details not OOD inheritance.

I see very few problems if the derived class has a 'trivial dtor', such
as the compiler generqted defaults and it is not created on the heap.

There are alot of useful and legal uses of public inheritance beside
classical OOP, one is CRTP which uses a templated base class instabced
with the name of the Derived tyoe as a template parameter, See boost
for lots of examples of this. One that comss to mind is iteratpr_facade.
which does all the grunt work of producing a valid STL interator if you
provide a few non virtual functions that describe the behavior of your
iterator. Nost of the boost provided iterators are derived from
iterator_facde, via iterator_adaptor.

Francis Glassborow

unread,
Jul 1, 2006, 2:00:53 PM7/1/06
to
In article <1151595195....@m73g2000cwd.googlegroups.com>, todma
<toddmars...@yahoo.com> writes

>But wait, do vector<> etc. have any virtual functions? if not then they
>can be derived from, they don't need virtual destructors, and can't be
>destroyed through pointers to base classes, right?

It rather depends on the meaning you are attributing to "can't". Doing
so wil result in undefined behaviour but the compiler will let you write
code that does this, it is just the language places no obligations on
the compiler wrt to the consequences.

However IMO, the real problem with public derivation from a concrete
class that does not have any virtual members is the potential for
unintended implicit conversions from derived to base.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

Lourens Veen

unread,
Jul 2, 2006, 8:09:35 AM7/2/06
to
Alan McKenney wrote:
>
> So, in accordance with *my* design principles, developed
> over 30 years of large-scale software development and
> maintenance, led me to do:
>
> struct KeywordData : public std::vector<Entry> { std::string
> keyword; };
> std::vector<KeywordData> tableData;
>
> So far, given how I use the class, I don't see a problem.
>
> It's quick to write, economical in concepts, requires no
> change to the part of the code that expected a std::vector,
> the meaning is obvious to anyone who reads the code, and the
> "gotchas" are obvious, at least to anyone who reads this
> newsgroup :-)

Interestingly, it's also a subtype in the Liskov sense of the word,
unlike a subclass which overrides a virtual member function and
changes the behaviour. I think this shows how Liskov-subtypes don't
make much sense in an OOP world, where objects can have very complex
behaviour. The only reason the concept does work here is because the
added part is plain old data.

Of course, whether it is a good idea (in the long term) to have a bare
data member in there is another question. I assume you have a good
reason not to use an std::map<std::string, std::vector<Entry> >?

Lourens

RenjithMohan

unread,
Jul 2, 2006, 4:35:43 PM7/2/06
to
Francis Glassborow wrote:

> In article <1151595195....@m73g2000cwd.googlegroups.com>, todma
> <toddmars...@yahoo.com> writes
> >But wait, do vector<> etc. have any virtual functions? if not then they
> >can be derived from, they don't need virtual destructors, and can't be
> >destroyed through pointers to base classes, right?
>
> It rather depends on the meaning you are attributing to "can't". Doing
> so wil result in undefined behaviour but the compiler will let you write
> code that does this, it is just the language places no obligations on
> the compiler wrt to the consequences.
>
> However IMO, the real problem with public derivation from a concrete
> class that does not have any virtual members is the potential for
> unintended implicit conversions from derived to base.

If that is the case really, what prevents the language from enforcing a
statement against it through the compiler.
We should consider things like adding capabilities to a hirearchy
through a veneer, where public inheritance is used with great
effectiveness.

template <typename T>
class CapVeneer : public T
{
typedef T ParentClass;
typedef CapVeneer<T> Class;

public:
int MyNewFunction();

};

Here a T can be replaced with CapVeneer<T> and it would have the new
MyNewFunction as a bonus. All related Ts can benefit from this, a
victory of CRTP.
what do you think about this?.

Raoul

unread,
Jul 2, 2006, 4:40:50 PM7/2/06
to
Markus Schoder wrote :

> If you non-trivially override virtual functions in a derived class it will
> not be a subtype (in general) according to the above definition since in
> terms of program behavior derived class objects will differ form base class
> objects.

Lourens Veen wrote :

> Interestingly, it's also a subtype in the Liskov sense of the word,
> unlike a subclass which overrides a virtual member function and
> changes the behaviour. I think this shows how Liskov-subtypes don't
> make much sense in an OOP world, where objects can have very complex
> behaviour.

Well, as I understand the LSP aims to keep invariant under type
substitution
the behavioural properties of objects of type T **as seen by the client
code
using such objects, according to the specification of T ** . It does
not aim to
keep invariant the observable behavior of the program, as that would
be indeed
pretty useless...

See "A Behavioral Notion of Subtyping", Barbara H. Liskov, Jeanette M.
Wing,
ACM Transactions on Programming Languages and Systems 1994

http://citeseer.ist.psu.edu/liskov94behavioral.html

Gene Bushuyev

unread,
Jul 3, 2006, 7:11:40 AM7/3/06
to
"Alan McKenney" <alan_mc...@yahoo.com> wrote in message
news:1151705066.1...@p79g2000cwp.googlegroups.com...
[...]

>
> The situation is that I have a class to implement a configuration
> table. The (private) member object that holds the table data was
> originally
>
> typedef std::vector<Entry> KeywordData
> std::vector<KeywordData> tableData;
[...]

> I then went to write my "print()" function, which prints out
> the contents of the table for debugging purposes,
> (one of my design principles: never create a complicated
> data structure without a "print()" function!) and
> realized that "tableData" didn't have the keyword.

So you did an error in the original design and now fixing it making another
design error.

>
> At first, in line with the suggestions in this thread, I tried
> making KeywordData a class:
>
> struct KeywordData { std::vector<Entry> data; std::string keyword; };
>
> but since I wanted to preserve the interface, I found myself
> writing forwarding functions for large parts of the std::vector
> interface, with frequent trips to the std::vector man page to
> get all the types just right.

Complaining about 10 minutes spent on typing is a lame excuse. There is nothing
difficult or error-prone writing forwarding functions, so much so, that PIMPL
idiom is a widely used practice. In my experience, programmers in my field
produce just around 100 lines of code a day in average in the long run; typing
being an infinitesimal part of program development cycle. Making correct design
takes probably 80% of the development cycle, being the single most important
part of the large-scale project.
Moreover, I very much doubt that the real life designs need to repeat exactly
all the functions of the interface of the contained classes. I've never seen
that in good designs (pimpl is a case of its own). In practice, I observed that
few functions need to be repeated, mostly new functions are created in order to
manage invariants. Otherwise, the class design is probably incorrect, because
its parts are acting autonomously, in which case a simple aggregation should be
considered.
Alternatively, people sometimes expose the contained classes through references.
E.g.

class KeywordData


{
std::vector<Entry> data;
std::string keyword;

public:
std::vector<Entry>& GetData() { return data; }
// ...
};

This is far better than inheriting, but should be used primarily as a variant of
aggregation theme; in general case, exposing the internals of the class through
non-const references leads to the possibilities of invariant violations, and
inconsistent states.

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
To see what is in front of one's nose needs a constant struggle ~ George Orwell

Carl Barron

unread,
Jul 3, 2006, 7:13:14 AM7/3/06
to
Lourens Veen <lou...@rainbowdesert.net> wrote:

> Alan McKenney wrote:

> > struct KeywordData : public std::vector<Entry> { std::string
> > keyword; };

> Interestingly, it's also a subtype in the Liskov sense of the word,


> unlike a subclass which overrides a virtual member function and
> changes the behaviour. I think this shows how Liskov-subtypes don't
> make much sense in an OOP world, where objects can have very complex
> behaviour. The only reason the concept does work here is because the
> added part is plain old data.
>

Std::string is not plain old datd:) If this is goimg to be used
in a context of runtime polymorphism, then the problem of no virtual
dtor() problem, still exists. If this is passed by reference/const
reference to
a routine that does not do tricks like store the addreess of the
reference, [the original KeywordData object] and then delete it
as an std::vector<...> *, all is fine.

Dave Harris

unread,
Jul 3, 2006, 5:25:21 PM7/3/06
to
alan_mc...@yahoo.com (Alan McKenney) wrote (abridged):

> However, just in the last hour, I find myself writing a class
> which is publicly derived from std::vector .
>
> The situation is that I have a class to implement a configuration
> table. The (private) member object that holds the table data was
> originally
>
> typedef std::vector<Entry> KeywordData
> std::vector<KeywordData> tableData;

That these are private does lessen the problem. It means the "public
inheritance" isn't really very public.


> struct KeywordData { std::vector<Entry> data; std::string keyword; };
>
> but since I wanted to preserve the interface, I found myself
> writing forwarding functions for large parts of the std::vector
> interface, with frequent trips to the std::vector man page to
> get all the types just right.

It sounds like you tried to add all the documented vector functions. I
don't think you needed to do that - especially as the variables are
private, meaning there was no chance of breaking client code. You only
need to add the functions you needed.

In fact, one of the benefits of wrapping the vector is to see how the
interface you really need differs from what vector provides. I have known
cases where I found I didn't need begin/end and iterators, or where I
didn't need random access. "struct KeywordData" lets your object be
itself. At best this leads to new insights about the data.

Another way in which the class can grow is by moving more code into the
new class. For example, if begin/end is needed by print and nothing else,
then making print a member means you can remove begin/end from the public
interface. Again this gives more insights as to what the class is really
about. Strive for minimal interfaces.


> and the "gotchas" are obvious, at least to anyone who reads
> this newsgroup :-)

Do you think so? The code which implicitly converts your class into the
base class may be in one place, and the code that deletes the base class
may be in another, so that it is not obviously wrong even to an
experienced programmer. Although that's unlikely to happen here, it's an
insidious problem.

The other gotcha is that names from the base class get injected into the
derived scope's scope. In the worst case, the base class has code like:

protected:
virtual void print();

and the print function you add overrides the one in the base class and so
gets called unexpectedly. Your current library vendor may not do anything
like that, but who knows what future ones will do? It's even possible that
the next C++ standard will add member functions to std::vector.

Is this gotcha obvious? Has it been mentioned in the thread before?

Inheritance is a tightly-coupled relationship, best avoided except when it
is needed.

-- Dave Harris, Nottingham, UK.

kanze

unread,
Jul 3, 2006, 5:26:58 PM7/3/06
to
Gene Bushuyev wrote:

> typing being an infinitesimal part of program development
> cycle.

Just a nit, because I agree in general with what you are saying
but... I spend a very large percent of my professional time
typing. I you had said, "typing code is just an infinitesimal
part of program development cycle", I would agree, but I type
when I'm designing, and even when I'm brainstorming. (I find I
tend to forget my best ideas later unless they're written down.)
About the only time I'm not typing is when I'm looking up
references or existing practice.

> Making correct design takes probably 80% of the development
> cycle, being the single most important part of the large-scale
> project.

Definitly, but doing correct design means typing. To begin
with, correct design is reviewed design, and what are the
reviewers going to work with if the design isn't written down.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Andrei Alexandrescu (See Website For Email)

unread,
Jul 4, 2006, 10:49:48 AM7/4/06
to
Alan McKenney wrote:
> struct KeywordData : public std::vector<Entry> { std::string keyword;
> };
> std::vector<KeywordData> tableData;

Congratulations, you've just invented std::pair.

When comparing approaches, it's always good to think hard about picking
the appropriate baseline. I agree with most of the points you're making
in defending your approach, but you're defending against the wrong
baseline. You shouldn't compare against private inheritance or parallel
vectors - just against

typedef pair<vector<Entry>, string> KeywordData;


Andrei

Alan McKenney

unread,
Jul 5, 2006, 6:09:52 AM7/5/06
to

Gene Bushuyev wrote:
> "Alan McKenney" <alan_mc...@yahoo.com> wrote in message
> news:1151705066.1...@p79g2000cwp.googlegroups.com...
> [...]

>


> So you did an error in the original design and now fixing it making another
> design error.

I don't agree that the original design was erroneous, at least
not until I added the requirement of a "print" function that
would include "keyword". Much of my work involves dealing
with requirements changes, this is different only in that
I was the one changing the requirement.

And I have yet to see any justification for calling the
final design a "design error", other than the fact that
it disobeys a rule of OOD. Since I'm not doing OOP here,
I don't see that as an issue.

> Complaining about 10 minutes spent on typing is a lame excuse. ...

Plus the time to test and maintain the code, and maybe
to explain over and over and over to other maintainers
(sometimes years later!) why the code is there. And to
do the same thing when you have to add or change the
forwarding functions because the requirements change.
(Which they will, frequently, over the life of the
product.)


I don't see a lot of appreciation in this newsgroup
for the fact that software development involves a lot
of trade-offs, and producing a 100 % "correct" design for
any particular component has a cost, which has to be
justified. And in some situations, a less that 100%
"correct" design may be the better choice.

Or that, more generally, for any rule, there is going
to be a situation where following the rule will result
in worse code that breaking it.


-- Alan McKenney

James Kanze

unread,
Jul 5, 2006, 8:26:24 PM7/5/06
to
Francis Glassborow wrote:
> In article <1151595195....@m73g2000cwd.googlegroups.com>, todma
> <toddmars...@yahoo.com> writes
>> But wait, do vector<> etc. have any virtual functions? if not
>> then they can be derived from, they don't need virtual
>> destructors, and can't be destroyed through pointers to base
>> classes, right?

> It rather depends on the meaning you are attributing to
> "can't". Doing so wil result in undefined behaviour but the
> compiler will let you write code that does this, it is just
> the language places no obligations on the compiler wrt to the
> consequences.

> However IMO, the real problem with public derivation from a
> concrete class that does not have any virtual members is the
> potential for unintended implicit conversions from derived to
> base.

And my experience, based on a number of large projects, is that
for things like std::iterator or std::unary_function, this is
just not a problem. I've seen lots of C++ code, written by
people who are not always experts, and I've never seen anyone
even declare a pointer with one of these types, let alone try to
delete through it.

(Note that I definitly agree that you shouldn't derive publicly
from std::vector. But I object to seeing this rule generalized
to "never". There are exceptions, and IMHO, they are valid
exceptions.)

--
James Kanze kanze...@neuf.fr


Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

James Kanze

unread,
Jul 5, 2006, 8:27:11 PM7/5/06
to
Gene Bushuyev wrote:
> "Bo Persson" <b...@gmb.dk> wrote in message

[...]


>> Try this snipet from the standard library:

>> template<class _ArgT, class _ResultT>
>> struct unary_function

> I already contended in my previous post, that simple convience
> template classes, that have little chances to be abused, and
> some template patterns are exempted. It's a reasonable
> exception from the rule.

So you agree that there are reasonable exceptions. And I
certainly agree that they aren't the usual case. All too often
in this sort of discussion, we end up having to agree to
disagree, but I have the impression here that we are to the
point where we can agree to agree---such uses are reasonable
(you just said so yourself), but are more or less exceptional,
and require (IMHO, anyway) specific documentatino, because they
don't represent the usual case.

--
James Kanze kanze...@neuf.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

James Kanze

unread,
Jul 5, 2006, 8:24:47 PM7/5/06
to

Why? Why is it so essential that the print function be a
member? Especially here, where the type is a member of a larger
class anyway?

> but since I wanted to preserve the interface, I found
> myself writing forwarding functions for large parts of
> the std::vector interface, with frequent trips to the
> std::vector man page to get all the types just right.

Again, since the type is an implementation detail of
configuration table. As such, there is absolutely no reason to
provide more interface than absolutely necessary. Any
additional interface is, in fact, a design error. (If the
additional interface is present because you are using a typedef,
fine. As long as the type remains private, you're still in
control. As soon as the type becomes public, however, you
definitly want to restrict the interface to be as narrow as
possible.)

On the whole, I'd say that you are following overly rigid dogma.
And that one of those dogma is even bad---it imposes something
you normally want to avoid.

--
James Kanze kanze...@neuf.fr


Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

James Kanze

unread,
Jul 5, 2006, 8:26:50 PM7/5/06
to
Francis Glassborow wrote:
> In article <1151320889....@b68g2000cwa.googlegroups.com>, kanze
> <ka...@gabi-soft.fr> writes
>> Public derivation defines a "is a" relationship. Public
>> inheritance is the obvious way to implement it. So much so
>> that I would say that public derivation implies public
>> inheritance. But it's not an if and only if relationship.

> And IMO, one of the strengths of C++ is that it provides
> alternative forms of inheritance to deal with cases where
> inheritance is not OO derivation.

In every case? What about std::unary_function, or
std::iterator. Both classes are very definitly designed to be
used as public base classes---they don't make any sense
otherwise. Neither corresponds to what I would consider an OO
base class.

--
James Kanze kanze...@neuf.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Gene Bushuyev

unread,
Jul 5, 2006, 8:25:31 PM7/5/06
to
"Alan McKenney" <alan_mc...@yahoo.com> wrote in message
news:1152047060....@m73g2000cwd.googlegroups.com...

>
> Gene Bushuyev wrote:
>> "Alan McKenney" <alan_mc...@yahoo.com> wrote in message
>> news:1151705066.1...@p79g2000cwp.googlegroups.com...
>> [...]
>
>>
>> So you did an error in the original design and now fixing it making another
>> design error.
>
> I don't agree that the original design was erroneous, at least
> not until I added the requirement of a "print" function that
> would include "keyword". Much of my work involves dealing
> with requirements changes, this is different only in that
> I was the one changing the requirement.

There are two types of requirements changes that are worth distinguishing. One
change involves design extension, when the existing code doesn't change and the
new code is added to add new required functionality (open-close principle). This
is a healthy way the designs grow. The other type of change in requirements
breaks the original design. Such change requires creating a new design, possibly
carefuly reusing bits and pieces of the existing design (e.g. cut & paste).
There are many temptations on this way taking a shortcut, or trying to reuse the
parts that don't really fit. In large scale projects it can lead to a tightly
coupled mess. Can you imagine a computer motherboard with thousands of cuts and
a bunch soldered wires on top. It's impossible to maintain or extend such
designs and everybody hates supporting them.

>> Complaining about 10 minutes spent on typing is a lame excuse. ...
>
> Plus the time to test and maintain the code, and maybe

Testing code is easier if the testability was one of the design quality
parameters. Maintanence cost of a correct design is low. Actually, if code is
100% correct maintanence cost is 0, since there is no tear and wear :-)

> to explain over and over and over to other maintainers
> (sometimes years later!) why the code is there. And to

Explain? Just give them a good book to read. I have a list of essential readings
here: http://www.gbresearch.com/software_resources.html

> do the same thing when you have to add or change the
> forwarding functions because the requirements change.
> (Which they will, frequently, over the life of the
> product.)

See above. If the change in requirements break design, and a new correct design
isn't created, then this project is in big trouble, it will turn into spaghetty
pretty quickly.

>
>
> I don't see a lot of appreciation in this newsgroup
> for the fact that software development involves a lot
> of trade-offs, and producing a 100 % "correct" design for
> any particular component has a cost, which has to be
> justified. And in some situations, a less that 100%
> "correct" design may be the better choice.

Everything comes with a cost. For good design you pay the biggest part upfront,
a bad design exacts a toll during its whole life time, in large designs leading
to a premature and ugly death. I would recommend Robert Glass's books and
articles that discuss many philosophical and psychological points of software
development. This is a good book to start with:
http://www.amazon.com/exec/obidos/ASIN/0321117425/gbresearch-20/104-5060517-6475154?creative=327641&camp=14573&adid=19EAPZD9HFSN2FCJZZMV&link_code=as1

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
To see what is in front of one's nose needs a constant struggle ~ George Orwell

James Kanze

unread,
Jul 5, 2006, 8:27:31 PM7/5/06
to
Gene Bushuyev wrote:
> "kanze" <ka...@gabi-soft.fr> wrote in message
> news:1151579722.5...@b68g2000cwa.googlegroups.com...
>> Gene Bushuyev wrote:
> [...]
>>> That pretty much restricts derivation to virtual functions,
>> If you don't have virtual functions, it is pretty clear that you
>> are not using C++ derivation to implement the design concept of
>> inheritance, but for some other reason.

> What are those other reasons?

In the case of std::iterator<>, providing typedef's. In
general, I often derive from traits classes for convenience
reasons; I think it's a common idiom.

> I'm repeating myself, but since nobody addressed it, I do it
> again. Public inheritance can be used for two purposes: to
> extend the base class overriding virtual functions
> (substitution principle), or to reuse the base class in
> derived. The later can be justified in some template
> patterns, but not in general case.

I think you're being overly restrictive. C++ derivation is an
implementation technique. It has certain, very specific results
within the language. I would not care to guess what techniques
people may or may not come up with.

It is a fact, I think, that C++ derivation was initially
conceived to implement OO inheritance, and that that is, even
today, by far its most widespread use. If I design a class to
be used as a base class for some other reason, I will take extra
pains in documenting that it is not the usual reason. But that
doesn't mean that any other reason is wrong. Or to pick up on
your words, the fact that something is not the general (or
usual) case doesn't make it wrong (although it may mean that
additional documentation is required).

(Actually, I'm not sure we disagree that much. Replace the word
"template" with "special" in your last sentence, and I"d have no
problem with it. The most frequent case---the default case, in
my mind---for public derivation, is OO inheritance. Anything
else is "special".)

--
James Kanze kanze...@neuf.fr


Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

Dave Harris

unread,
Jul 6, 2006, 6:17:45 PM7/6/06
to
SeeWebsit...@erdani.org (Andrei Alexandrescu (See Website For
Email)) wrote (abridged):

> > struct KeywordData : public std::vector<Entry> { std::string keyword;
> > };
> > std::vector<KeywordData> tableData;
>
> Congratulations, you've just invented std::pair.

I think "first" is rather a poor name for the member, so I'd prefer the
Alan McKenney's initial solution:

struct KeywordData { std::vector<Entry> data; std::string keyword; };

(Although "data" is a poor name too; if they are entries I'd call them
"entries".)

Either way it changes the interface to the object. Code that looked like:

int value = keywordData.front().value;

won't compile any more. Instead we need:

int value = keywordData.data.front().value;

which he rejected. He didn't say why, but long chains of dots like that
kinda go against the "Law of Demeter" and it makes me a bit uncomfortable.

-- Dave Harris, Nottingham, UK.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

0 new messages