Choosing between public and private inheritance

D

Dennis Jones

Hi,

I have created a couple of template classes to model tree structures. The
base class represents a generic tree structure, and derived classes provide
modified interfaces and implementations:

template <typename T>
class GenericTree
{
public:
typedef treenode<T> node_type;

class ChildIterator_t
{
};
};

template <typename Key, typename T>
class MapTree : private GenericTree<T>
{

public:
typedef GenericTree<T> tree_type;
typedef Key key_type;
typedef T mapped_type;
typedef tree_type::node_type node_type;

typedef tree_type::ChildIterator_t ChildIterator_t;

void AddChild( const key_type &parent_key,
const key_type &key,
const mapped_type &Item )
{
node_type *ParentNode = get ParentNode from parent_key
AddChild( ParentNode, key, Item );
}
protected:
void AddChild( node_type *ParentNode,
const key_type key,
const mapped_type &Item )
{
}
};

typedef MapTree<int, MySpecialType> map_tree_type;
class MySpecialTree : private map_tree_type
{
public:
typedef map_tree_type inherited;
typedef inherited::node_type node_type;

typedef map_tree_type::ChildIterator_t ChildIterator_t;

void AddChild( node_type *ParentNode,
const key_type key,
const mapped_type &Item )
{
inherited::AddChild( ParentNode, key, Item );
}
};

Note that I've used private inheritance to model the
"implemented-in-terms-of" relationship between the classes, rather than
public inheritance modelling an "is-a" relationship.

Private inheritance seemed to make sense at the time, but as I begin to use
the MySpecialTree class, I often find myself needing to use methods that
exist at higher levels of the hierarchy, and the only way to do that with
private inheritance is to re-implement the methods in terms of the ancestor
class(es) (see AddChild). The same goes for typedefs (see node_type and
ChildIterator_t). This seems like a big waste of time and effort . . . not
to mention the mess it makes from what seems like a lot of unncesssary
declarations.

So, here's my question: how do I decide whether to use public or private
inheritance? If I switch to public inheritance, all of the extra
declarations and method implementations can go away. On the other hand, I'm
not sure public inheritance is what I want either, since the derived class
interfaces may be different from those of their ancestors.

What criteria should one use when making this kind of a design decision?

Thanks,

Dennis
 
J

James Kanze

"Dennis Jones" <[email protected]> wrote:

[...]
Public inheritance assumes substitutability:
[http://preview.tinyurl.com/w3car]

Not always. At least not for some meanings of "inheritance".
Surely you don't think that every class inheriting from
std::iterator is substitutable.

This is really an issue of whether one is talking about design
or implementation technique. Regretfully, there's no
established vocabulary to make the distinction. I tend to use
"inheritance" for the implementation technique, and "derivation"
for the design concept---in these terms, not all inheritance is
used to implement derivation. But clearly, this distinction is
not in widespread use or well established.
Can a MapTree<Key, T> be use anywhere a GenericTree<T> can be
used? Can you use a MySpecialTree anywhere you are using a
MapTree<int, MySpecialType>?
Are there even functions in your code that pass GenericTree<T> or
MapTree<int, MySpecialType> by reference or pointer?

I tend to use a slightly different vocabulary (although the
results are pretty much the same). If the class I'm deriving
from defines a contract, and my class guarantees to support that
contract, then the inheritance should be public. Otherwise not.
And if the reason I'm inheriting isn't to "derive" (using the
distinction above), other rules hold.
 
D

Dennis Jones

Daniel T. said:
So, here's my question: how do I decide whether to use public or private
inheritance? If I switch to public inheritance, all of the extra
declarations and method implementations can go away. On the other hand,
I'm
not sure public inheritance is what I want either, since the derived
class
interfaces may be different from those of their ancestors.

What criteria should one use when making this kind of a design decision?

Public inheritance assumes substitutability:
[http://preview.tinyurl.com/w3car]

Can a MapTree<Key, T> be use anywhere a GenericTree<T> can be used? Can
you use a MySpecialTree anywhere you are using a MapTree<int,
MySpecialType>?

Theoretically speaking, yes. But practically speaking, no. The application
will only use 'MySpecialTree'. But I wanted to create it such that higher
level classes could be re-used in other applications. Otherwise, I would
have just written a monolithic 'MySpecialTree' class without using templates
or inheritance at all.

Are there even functions in your code that pass GenericTree<T> or
MapTree<int, MySpecialType> by reference or pointer?

No (see my response to the previous question). 'GenericTree' was created to
provide the basic tree structure and its operations. 'MapTree' maps keys to
nodes (like std::map<>). 'MySpecialTree' is essentially a wrapper around
'MapTree' to provide the locking necessary to make 'MapTree' usable in a
multi-threading environment.

After thinking about this a little bit more, I think public inheritance (at
least between 'GenericTree' and 'MapTree') might be the better choice.
Otherwise, I'm writing a bunch of functions that do little more than forward
calls to derived classes. The relationship between 'MapTree' and
'MySpecialTree' is a little bit different though. Since I need to ensure
stability in a multi-threading environment, I wouldn't want to allow access
to functions that could operate withou the necessary locking. So, I think
maybe the inheritance of 'MySpecialTree' from 'MapTree' should remain
private.

Any other comments/suggestions?

- Dennis
 

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,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top