container access design headache

Discussion in 'C++' started by TheFerryman, May 5, 2004.

  1. TheFerryman

    TheFerryman Guest

    How bad is it to include a non const accessor to a container of
    objects? For instance

    template <class WheelType>
    class CarBase
    {
    typedef std::list<WheelType*> WheelList;

    private:

    //for the sake of this example, assume there can be any number
    //of wheels
    WheelList m_Wheels;

    //other components

    public:

    const WheelList& GetWheels()const{return m_Wheels;}
    WheelList& GetWheels(){return m_Wheels;}

    //other car related methods
    };


    I think this doesn't look good because I may as well make the
    WheelList public... but I hate making member variables public unless
    the class is a simple data structure (which this isn't, the real-world
    examples are complex)

    But if I only have the const accessor how should a client gain access
    to the wheels so they can change their properties? (If I create an
    iterator class to iterate through the objects how is that any
    different to allowing public access)

    This thing keeps going around and around my head and I think I'm
    starting to obsess on the problem so any help will be greatly
    appreciated. What do *you* do in these circumstances?
    TheFerryman, May 5, 2004
    #1
    1. Advertising

  2. TheFerryman

    Leor Zolman Guest

    On Wed, 05 May 2004 13:51:50 +0100, TheFerryman <> wrote:

    >How bad is it to include a non const accessor to a container of
    >objects? For instance
    >
    >template <class WheelType>
    >class CarBase
    >{
    > typedef std::list<WheelType*> WheelList;
    >
    >private:
    >
    > //for the sake of this example, assume there can be any number
    > //of wheels
    > WheelList m_Wheels;
    >
    > //other components
    >
    >public:
    >
    > const WheelList& GetWheels()const{return m_Wheels;}
    > WheelList& GetWheels(){return m_Wheels;}
    >
    > //other car related methods
    >};
    >
    >
    >I think this doesn't look good because I may as well make the
    >WheelList public... but I hate making member variables public unless
    >the class is a simple data structure (which this isn't, the real-world
    >examples are complex)
    >
    >But if I only have the const accessor how should a client gain access
    >to the wheels so they can change their properties? (If I create an
    >iterator class to iterate through the objects how is that any
    >different to allowing public access)
    >
    >This thing keeps going around and around my head and I think I'm
    >starting to obsess on the problem so any help will be greatly
    >appreciated. What do *you* do in these circumstances?


    I think you're having difficulty because of the interface you've chosen. In
    a typical collection of some kind, the "get" and "set" functionality isn't
    going to be abstracted in terms of getting and putting "the entire
    collection", but rather individual elements of the collection. If you were
    to separate out "getting" from "setting", then the result of getting could
    be a value (rather than a ref), and setting could be sanity-checked. The
    way you treat the wheel list doesn't take advantage of any of that; so for
    all intents and purposes, you may as well have m_Wheels be public if that's
    all the functionality you want.

    I think you need to decide whether CarBase is going to concern itself with
    individual Wheels or not. If so, then "get" and "set" functionality should
    be provided for individual Wheels if you really want CarBase to have some
    added value. If not, then WheelList should be a user-defined class in its
    own right, perhaps implemented in terms of a list (or not), so that after
    obtaining a handle to it from CarBase via GetWheels, the client would still
    have to go thorough WheelLists's (presumably safe) interface to munge with
    the Wheel List. Make any sense?
    -leor

    --
    Leor Zolman --- BD Software --- www.bdsoft.com
    On-Site Training in C/C++, Java, Perl and Unix
    C++ users: download BD Software's free STL Error Message Decryptor at:
    www.bdsoft.com/tools/stlfilt.html
    Leor Zolman, May 5, 2004
    #2
    1. Advertising

  3. TheFerryman wrote:
    > How bad is it to include a non const accessor to a container of
    > objects? For instance
    >
    > template <class WheelType>
    > class CarBase
    > {
    > typedef std::list<WheelType*> WheelList;
    >
    > private:
    >
    > //for the sake of this example, assume there can be any number
    > //of wheels
    > WheelList m_Wheels;
    >
    > //other components
    >
    > public:
    >
    > const WheelList& GetWheels()const{return m_Wheels;}
    > WheelList& GetWheels(){return m_Wheels;}
    >
    > //other car related methods
    > };
    >
    >
    > I think this doesn't look good because I may as well make the
    > WheelList public...
    > but I hate making member variables public unless
    > the class is a simple data structure (which this isn't, the real-world
    > examples are complex)


    In general would avoid that approach, it exposes the implementation of
    the CarBase class too much. If you would decide to use another
    container, or decide not to store pointers, it would break code the uses
    the CarBase class.

    > But if I only have the const accessor how should a client gain access
    > to the wheels so they can change their properties? (If I create an
    > iterator class to iterate through the objects how is that any
    > different to allowing public access)


    Iterators do a better job of hidding implementation details and give the
    CarBase class more control what clients can do and what not. If the
    CarBase class returns a reference to m_Wheels, clients can do what event
    they like with WheelList, including insert and removing elements. If
    CarBase has a (non-const) iterator clients can only manipulate WheelType
    objects. The iterator could also control which members of the WheelType
    objects can be accessed.

    > This thing keeps going around and around my head and I think I'm
    > starting to obsess on the problem so any help will be greatly
    > appreciated. What do *you* do in these circumstances?


    Think carefully about the interface of the CarBase class, and consider
    carefully what the clients should be able to do with it. Don't expose
    more than you have to, this makes it easier to change the implementation
    later.
    --
    Peter van Merkerk
    peter.van.merkerk(at)dse.nl
    Peter van Merkerk, May 5, 2004
    #3
  4. TheFerryman

    bartek Guest

    TheFerryman <> wrote in
    news::

    > How bad is it to include a non const accessor to a container of
    > objects? For instance


    (...)

    When you want to be able to modify the elements held by the container, then
    there's no other way than make them exposed. Why do you think it is bad?

    > But if I only have the const accessor how should a client gain access
    > to the wheels so they can change their properties? (If I create an
    > iterator class to iterate through the objects how is that any
    > different to allowing public access)


    This is how containers work. They *hold* objects, not *hide* them. Unless
    of course you want it otherwise in your implementation.

    --
    :: bartekd [at] o2 [dot] pl
    bartek, May 5, 2004
    #4
  5. "TheFerryman" <> wrote
    > How bad is it to include a non const accessor to a container of
    > objects? For instance
    >
    > template <class WheelType>
    > class CarBase
    > {
    > typedef std::list<WheelType*> WheelList;
    >
    > private:
    >
    > //for the sake of this example, assume there can be any number
    > //of wheels
    > WheelList m_Wheels;
    >
    > //other components
    >
    > public:
    >
    > const WheelList& GetWheels()const{return m_Wheels;}
    > WheelList& GetWheels(){return m_Wheels;}
    >
    > //other car related methods
    > };
    >
    >
    > I think this doesn't look good because I may as well make the
    > WheelList public... but I hate making member variables public unless
    > the class is a simple data structure (which this isn't, the real-world
    > examples are complex)
    >
    > But if I only have the const accessor how should a client gain access
    > to the wheels so they can change their properties? (If I create an
    > iterator class to iterate through the objects how is that any
    > different to allowing public access)
    >
    > This thing keeps going around and around my head and I think I'm
    > starting to obsess on the problem so any help will be greatly
    > appreciated. What do *you* do in these circumstances?


    I think it's a question of logical design. By just exposing the underlying
    WheelList, you're saying that it's perfectly valid for any outside entity to
    remove every wheel, or to add 30000 wheels, or to make every wheel a different
    size, or to make some elements null pointers but leave them in the list, or make
    some of the pointers point to shared objects, and so on. In other words, it's a
    free-for-all.

    In a clean design, if the WheelList is the responsibility of CarBase, then the
    interface should restrict access to only the operations that CarBase allows. For
    example, CarBase might enforce the same WheelType on a given axel, or even the
    same WheelType for the entire car (though this might be overly restrictive).
    CarBase should probably restrict the number of wheels that can be set (the exact
    number being provided by a virtual function that's overridden in derived
    classes). CarBase should DEFINITELY manage the lifetimes of the objects pointed
    to by your WheelType pointers and not allow outside entities to meddle. As a
    general rule, a class should take responsibility for all of its data members and
    enforce its internal consistency unless it's a mere "holder" like std::pair<>.

    Claudio Puviani
    Claudio Puviani, May 5, 2004
    #5
  6. TheFerryman

    Siemel Naran Guest

    "TheFerryman" <> wrote in message

    > template <class WheelType>
    > class CarBase
    > {
    > typedef std::list<WheelType*> WheelList;
    >
    > private:
    >
    > //for the sake of this example, assume there can be any number
    > //of wheels
    > WheelList m_Wheels;
    >
    > //other components
    >
    > public:
    >
    > const WheelList& GetWheels()const{return m_Wheels;}
    > WheelList& GetWheels(){return m_Wheels;}
    >
    > //other car related methods
    > };


    > But if I only have the const accessor how should a client gain access
    > to the wheels so they can change their properties? (If I create an
    > iterator class to iterate through the objects how is that any
    > different to allowing public access)


    As others point out, returning iterators don't allow you to add or delete
    wheels. But there's mode. You can have the iterator's operator* return a
    smart reference. This is a user defined class that behaves like a builtin
    reference for most practical purposes. It typically has a protected
    constructor, and overrides operator= as in
    WheelList::reference::eek:perator=(const Wheel&) which can do additional
    checking, such as throwing an exception if you try to put a wrong type of
    wheel on a certain car.

    > This thing keeps going around and around my head and I think I'm
    > starting to obsess on the problem so any help will be greatly
    > appreciated. What do *you* do in these circumstances?


    Remember, it's often a tradeoff between perfect design, performance, and
    time + budget.
    Siemel Naran, May 7, 2004
    #6
    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. Vivi Orunitia
    Replies:
    11
    Views:
    4,473
    Martijn Lievaart
    Feb 4, 2004
  2. Maitre Bart
    Replies:
    2
    Views:
    521
    Maitre Bart
    Feb 11, 2004
  3. Steven T. Hatton
    Replies:
    4
    Views:
    3,896
    Rob Williscroft
    Dec 5, 2004
  4. Replies:
    4
    Views:
    798
    Daniel T.
    Feb 16, 2006
  5. wolverine
    Replies:
    2
    Views:
    450
    Marcus Kwok
    Jul 24, 2006
Loading...

Share This Page