Choosing between public and private inheritance

Discussion in 'C++' started by Dennis Jones, Apr 16, 2009.

  1. Dennis Jones

    Dennis Jones Guest

    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
     
    Dennis Jones, Apr 16, 2009
    #1
    1. Advertising

  2. Dennis Jones

    James Kanze Guest

    On Apr 17, 3:12 am, "Daniel T." <> wrote:
    > In article <xtxFl.1080$>,
    > "Dennis Jones" <> 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.

    --
    James Kanze (GABI Software) email:
    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, Apr 17, 2009
    #2
    1. Advertising

  3. Dennis Jones

    Dennis Jones Guest

    "Daniel T." <> wrote in message
    news:-sjc.supernews.net...
    > In article <xtxFl.1080$>,


    >> 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
     
    Dennis Jones, Apr 17, 2009
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Charles A. Lackman
    Replies:
    1
    Views:
    1,445
    smith
    Dec 8, 2004
  2. SpamProof
    Replies:
    0
    Views:
    641
    SpamProof
    Oct 21, 2003
  3. qazmlp
    Replies:
    19
    Views:
    828
    Daniel T.
    Feb 4, 2004
  4. DaveLessnau
    Replies:
    3
    Views:
    449
    Howard
    May 16, 2005
  5. Mr Flibble
    Replies:
    0
    Views:
    321
    Mr Flibble
    Jun 6, 2006
Loading...

Share This Page