Composition versus Implementation Inheritance

C

chsalvia

Most modern sources on C++ design say that composition is usually
preferable to implementation inheritance because inheritance tends to
lead to problems down the road unless it follows a strict model
allowing substitution, where each derived class has an "is-a"
relationship with the base class.

I was wondering, however, if implementation inheritance (private
inheritance) might be a better idea in some cases. Consider the SGI C+
+ extension implementation of hash_set and hash_map. Both hash_set
and hash_map use composition to reuse code from an internal class.
They each have an internal hash_table class, which implements the
basic functions of a hash table. The hash_set and hash_map class use
delegation to access the functionality of the internal hash_table
class. Google's sparse hash map/hash set also uses the same design
scheme.

This is a nice clean design, except one thing about it really bothers
me. There's nothing preventing someone from instantiating an instance
of the internal hash_table class somewhere else. Unlike an abstract
base class, or a base class with a protected constructor, the internal
hash_table "base" class can be instantiated anywhere, even though this
would be useless.

But if the hash_set and hash_map class used private inheritance to
access the hash_table class, rather than composition/delegation, then
the hash_table class could have been written with a protected
constructor so that it couldn't be instantiated outside of a derived
class.

Plus, all the usual arguments against implementation inheritance
wouldn't really apply, since the hash_set and hash_map classes are not
designed to be inherited from anyway. (They have no virtual
destructor, like all STL-ish classes.)

Does anyone agree with me here? Or am I missing some more compelling
reasons to stick with composition/delegation in this case?
 
D

Daniel T.

Most modern sources on C++ design say that composition is usually
preferable to implementation inheritance because inheritance tends to
lead to problems down the road unless it follows a strict model
allowing substitution, where each derived class has an "is-a"
relationship with the base class.

I was wondering, however, if implementation inheritance (private
inheritance) might be a better idea in some cases. Consider the SGI C+
+ extension implementation of hash_set and hash_map. Both hash_set
and hash_map use composition to reuse code from an internal class.
They each have an internal hash_table class, which implements the
basic functions of a hash table. The hash_set and hash_map class use
delegation to access the functionality of the internal hash_table
class. Google's sparse hash map/hash set also uses the same design
scheme.

This is a nice clean design, except one thing about it really bothers
me. There's nothing preventing someone from instantiating an instance
of the internal hash_table class somewhere else. Unlike an abstract
base class, or a base class with a protected constructor, the internal
hash_table "base" class can be instantiated anywhere, even though this
would be useless.

The question that immediately comes to mind here is: Why should this
bother you? What's wrong with reusable code?
Does anyone agree with me here? Or am I missing some more compelling
reasons to stick with composition/delegation in this case?

I'm not sure yet.
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Most modern sources on C++ design say that composition is usually
preferable to implementation inheritance because inheritance tends to
lead to problems down the road unless it follows a strict model
allowing substitution, where each derived class has an "is-a"
relationship with the base class.

I was wondering, however, if implementation inheritance (private
inheritance) might be a better idea in some cases. Consider the SGI C+
+ extension implementation of hash_set and hash_map. Both hash_set
and hash_map use composition to reuse code from an internal class.
They each have an internal hash_table class, which implements the
basic functions of a hash table. The hash_set and hash_map class use
delegation to access the functionality of the internal hash_table
class. Google's sparse hash map/hash set also uses the same design
scheme.

This is a nice clean design, except one thing about it really bothers
me. There's nothing preventing someone from instantiating an instance
of the internal hash_table class somewhere else. Unlike an abstract
base class, or a base class with a protected constructor, the internal
hash_table "base" class can be instantiated anywhere, even though this
would be useless.

So what if they can be instantiated, what harm would it do. As you say
it will probably be useless but you can't know the needs of every
developer out there. I think this is kind of making it impossible to
inherit from a class, I can't see any need for it. All it would
accomplish would be to prevent possible ways of implementation.

Since you can't anticipate all the requirements that might be placed on
your application in the future you should try to not artificially limit
the extensibility of your code (unless it makes it easier to satisfy the
current requirement).
 
C

chsalvia

I suppose I tend to think that, from a design point of view, if it
doesn't make any sense to instantiate a certain class outside of
another class, than this should be reflected somehow in the code, e.g.
by having a protected constructor.

It's true that you can never anticipate all the future requirements of
developers down the road, but doing so would not really limit
extensibility, because a future develop can always use private
inheritance if they want to extend the class.
 
D

Daniel T.

I suppose I tend to think that, from a design point of view, if it
doesn't make any sense to instantiate a certain class outside of
another class, than this should be reflected somehow in the code, e.g.
by having a protected constructor.

It's true that you can never anticipate all the future requirements of
developers down the road, but doing so would not really limit
extensibility, because a future develop can always use private
inheritance if they want to extend the class.

Which defeats the purpose of making the constructor protected, so why
bother?

The fact is, we have a class that has already been used in two contexts,
why assume that it wouldn't be useful in any others?

On the other hand, we are talking about a class that is not documented
and therefore cannot be expected to perform in any particular way so
anyones use of that class outside of those two contexts is hazardous.

You are asking here why use composition over private inheritance. How
about we turn the question around, why use private inheritance over
composition? Now that question has a solid answer, there are things that
you can do with private inheritance that you simply can't do with
composition, and if you need or want to do those things, then private
inheritance is what you use.

So now we can ask your original question again. If we are not using the
features that private inheritance provides, then we are telling
developers something about our class by no using private inheritance.
Composition sends a message to anyone looking at the class, "don't
bother worrying about me doing x, or y because that can't be done with a
composition relationship.
 
C

chsalvia

Which defeats the purpose of making the constructor protected, so why
bother?

The fact is, we have a class that has already been used in two contexts,
why assume that it wouldn't be useful in any others?

The purpose of making the constructor protected would be to basically
warn developers that this class should not be used on its own.
However, if some developer wanted to create a different type of hash
container some day, then that could be accomplished through private
inheritance. This way, a developer would need to specifically have in
mind the goal of extending the class in order to use the class. The
possibility of simply declaring an instance of the class somewhere
else would be eliminated.
On the other hand, we are talking about a class that is not documented
and therefore cannot be expected to perform in any particular way so
anyones use of that class outside of those two contexts is hazardous.

You are asking here why use composition over private inheritance. How
about we turn the question around, why use private inheritance over
composition? Now that question has a solid answer, there are things that
you can do with private inheritance that you simply can't do with
composition, and if you need or want to do those things, then private
inheritance is what you use.

So now we can ask your original question again. If we are not using the
features that private inheritance provides, then we are telling
developers something about our class by no using private inheritance.
Composition sends a message to anyone looking at the class, "don't
bother worrying about me doing x, or y because that can't be done with a
composition relationship.

Basically, it seems you're saying that the possible danger of
declaring a class outside of its appropriate context is not a
sufficient reason by itself to use private inheritance. Perhaps
you're right about that. Obviously, the SGI developers, who are much
more experienced than I am, thought that composition was a better
solution.

I was just thinking that in a case where you have class A, B and C,
where B and C use A internally, and declaring A anywhere else would be
senseless or possibly dangerous, it would be beneficial to somehow
restrict developers from instantiating A, *unless* they are
specifically trying to extend A, in which case they're probably well
aware of how A works. Otherwise, the only thing preventing someone
from instantiating A anywhere would be a warning in the source or
something.
 
D

Daniel T.

"Daniel T." <[email protected]> wrote:
Basically, it seems you're saying that the possible danger of
declaring a class outside of its appropriate context is not a
sufficient reason by itself to use private inheritance.

No, I'm saying that even if you do declare all class' constructors
protected, the class can still be used outside of its appropriate
context.
I was just thinking that in a case where you have class A, B and C,
where B and C use A internally, and declaring A anywhere else would
be senseless or possibly dangerous, it would be beneficial to
somehow restrict developers from instantiating A, *unless* they are
specifically trying to extend A, in which case they're probably well
aware of how A works.

If a library vendor has developed A for internal use (i.e., they have
not documented it,) it is "senseless or possibly dangerous" for anybody
other than them to use it, *even* if they are specifically trying to
extend it. Being "well aware of how A works" is irrelevant because the
vendor can make major changes to the way A works between versions (it is
not a published interface.)
<http://www.martinfowler.com/ieeeSoftware/published.pdf>

It would probably be nice to have some form of library level access
privileges, however C++ doesn't have anything like that and I think
abusing class level privileges in an attempt to simulate it is
inappropriate.
 
J

James Kanze

So what if they can be instantiated, what harm would it do. As you say
it will probably be useless but you can't know the needs of every
developer out there.

More to the point: if it's really useless, you don't have to do
anything to prevent it, since no one will do it.

In this case, there might be a case to argue that the base class
isn't adequately documented for use by others. As far as I can
tell, there's absolutely no guarantee that it will even be
present in the next release, or have the same interface if it
is. But again, I'd say that this is the user's problem. If one
is stupid enough to use some undocumented interface, then one
deserves whatever happens. (And realistically, there are many
cases where you cannot really avoid it.)
I think this is kind of making it impossible to
inherit from a class, I can't see any need for it. All it would
accomplish would be to prevent possible ways of implementation.
Since you can't anticipate all the requirements that might be
placed on your application in the future you should try to not
artificially limit the extensibility of your code (unless it
makes it easier to satisfy the current requirement).

You're code is really only extensible in ways you've planned for
and documented. But let's face it, only a fool would try to use
something that wasn't planned for and documented. (It's not
as though you might accidentally use it, as a result of a typo.)
 
J

James Kanze

I suppose I tend to think that, from a design point of view, if it
doesn't make any sense to instantiate a certain class outside of
another class, than this should be reflected somehow in the code, e.g.
by having a protected constructor.

The usual way is by encapsulating it in something like:
//!@implementation
// class definition here...
//!@end
That way, it doesn't show up in the documentation, and no one
is even aware of it's existance.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top