Passing derived class object array in place of base class object array

Discussion in 'C++' started by justanotherguy63@yahoo.com, Dec 2, 2004.

  1. Guest

    Hi,

    I am designing an application where to preserve the hierachy and for
    code substitability, I need to pass an array of derived class object in
    place of an array of base class object. Since I am using vector
    class(STL), the compiler does not allow me to do this.

    I do realize there is a pitfall in this approach(size of arrays not
    matching etc), but I wonder how to get around this problem. I have a
    class hierachy with abstract base class and all I wonder why the
    principle of passing a derived class reference in place of base class
    is not extended to arrays. After all, we are making the code more
    substitutable right? How do we achieve substitutability in this case?
    To me at least, not having to make needless changes to code and having
    the ability to sort things out dynamically using inheritance has always
    sounded crisp.

    Also, does this problem mean there is some deficiency in my application
    design? Any light you throw on this will be greatly appreciated.
    Thanks.
    justanotherguy
     
    , Dec 2, 2004
    #1
    1. Advertising

  2. broeni Guest

    wrote:
    > Hi,
    >
    > I am designing an application where to preserve the hierachy and for
    > code substitability, I need to pass an array of derived class object

    in
    > place of an array of base class object. Since I am using vector
    > class(STL), the compiler does not allow me to do this.
    >
    > I do realize there is a pitfall in this approach(size of arrays not
    > matching etc), but I wonder how to get around this problem. I have a
    > class hierachy with abstract base class and all I wonder why the
    > principle of passing a derived class reference in place of base class
    > is not extended to arrays. After all, we are making the code more
    > substitutable right? How do we achieve substitutability in this case?
    > To me at least, not having to make needless changes to code and

    having
    > the ability to sort things out dynamically using inheritance has

    always
    > sounded crisp.
    >
    > Also, does this problem mean there is some deficiency in my

    application
    > design? Any light you throw on this will be greatly appreciated.
    > Thanks.
    > justanotherguy


    Why do you not write a small wrapper class around std::vector?

    #include <vector>
    #include <memory>

    class BaseVector {
    public:
    typedef std::vector<Base*> Vector;
    public:
    // delete contents of vector_.
    ~BaseVector();
    // copy contents of vector_.
    BaseVector(const BaseVector& rhs);
    // copy contents of vector_.
    BaseVector& operator=(const BaseVector& rhs);
    public: // adding elements
    // add an element, copying, see 1) below
    void push_back(const Base& base);
    // add an element: takes ownership.
    void push_back(std::auto_ptr<Base*> base);
    public: // wrappers to vector_ as needed, e.g.:
    // number of elements
    Vector::size_type size() const;
    private:
    Vector vector_;
    };

    1) requires something like:
    class Base {
    public:
    // create a copy of the class.
    std::auto_ptr<Base*> clone() const = 0;
    };

    Stephan Brönnimann

    Open source rating and billing engine for communication networks.

    P.S. I'm posting via Google: with their new beta version I can't get a
    proper
    indentation in the preview!?
     
    broeni, Dec 2, 2004
    #2
    1. Advertising

  3. Tom Widmer Guest

    On 2 Dec 2004 00:51:28 -0800, wrote:

    >Hi,
    >
    >I am designing an application where to preserve the hierachy and for
    >code substitability, I need to pass an array of derived class object in
    >place of an array of base class object. Since I am using vector
    >class(STL), the compiler does not allow me to do this.


    I think with "business" entities, the kind of class that has a base
    class, you would typically store a vector of pointers. e.g.
    std::vector<Derived*> or std::vector<shared_ptr<Derived> >. Usually
    such entities aren't copyable, so can't be placed in containers
    directly. In any case, this level of indirection is useful.

    >I do realize there is a pitfall in this approach(size of arrays not
    >matching etc), but I wonder how to get around this problem. I have a
    >class hierachy with abstract base class and all I wonder why the
    >principle of passing a derived class reference in place of base class
    >is not extended to arrays. After all, we are making the code more
    >substitutable right? How do we achieve substitutability in this case?
    >To me at least, not having to make needless changes to code and having
    >the ability to sort things out dynamically using inheritance has always
    >sounded crisp.


    If you have a std::vector<Derived*>, you can create a vector<Base*>
    simply with:
    std::vector<Base*>(v.begin(), v.end());
    and pass that. It will only involve a single memory allocation (even
    in the smart pointer case), which isn't bad.

    It efficiency is a problem, then you do have an alternative that
    should work for single, non-virtual inheritence (where the address of
    the derived object usually matches that of the base one). It is
    undefined behaviour though, so only use it if profiling identifies a
    problem:

    std::vector<Base*> const& vb =
    reinterpret_cast<std::vector<Base*>&>(vd);

    >Also, does this problem mean there is some deficiency in my application
    >design? Any light you throw on this will be greatly appreciated.


    Well, you might find that you can get away with having a
    std::vector<Base*> all the time anyway, and do away with the
    vector<Derived*>.

    Tom
     
    Tom Widmer, Dec 2, 2004
    #3
  4. test
     
    =?iso-8859-1?q?Stephan_Br=F6nnimann?=, Dec 2, 2004
    #4
  5. wrote:
    > I am designing an application where to preserve the hierachy and for
    > code substitability, I need to pass an array of derived class object in
    > place of an array of base class object. Since I am using vector
    > class(STL), the compiler does not allow me to do this.


    Object orientation meets reality... There are actually languages
    where something like this is supported but it is inherently broken:
    An array of derived IS-NOT-A array of base, i.e. passing an array of
    derived where an array of base is expected is a violation of the
    Liskov Substition Principle: In an array of base, you should be able
    to place a base object. Of course, this would mean that an array of
    derived actually holds both derived and base objects or possibly
    other derived objects which is not possible and thus proving that
    it is a violation of LSP. Since I have seen answers trying to
    address the problem by using pointers, note that the same LSP
    violation applies to arrays of pointers.

    OK, after addressing why it is conceptually nonsense to treat an
    array of derived as an array of base, lets have a look why it does
    not work in C++ from a technical point of view: in C++ the expression
    'a' is effectively just '*(a + i)' where 'a + i' just computes
    the address by adding 'i * sizeof(a[0])' to 'a'. Since generally
    'sizeof(Base) != sizeof(Derived)', this gives a technical reason why
    you cannot access an array of derived as an array of base, even after
    forcing it through a reinterpret_cast'. The same applies, of course,
    to data structures internally using arrays like 'std::vector' or
    'std::deque'.

    > I do realize there is a pitfall in this approach(size of arrays not
    > matching etc), but I wonder how to get around this problem. I have a
    > class hierachy with abstract base class and all I wonder why the
    > principle of passing a derived class reference in place of base class
    > is not extended to arrays. After all, we are making the code more
    > substitutable right? How do we achieve substitutability in this case?


    Do you really need the class hierarchy or are you using it because
    it "always sounded crisp"? If the latter, throw it out as fast as you
    can! Object orientation has some merit but it is in no way a panacea
    and it is grossly overused (well, at least the dynamic polymorphism
    stuff is; I'm using encapsulation all the time but that is not the
    central theme assumed as object orientation by most people).

    Assuming you really need dynamic polymorphism for the stuff you do
    (which is in my experience actually relatively unlikely; there are
    a few uses but much less than is typically assumed), here is what
    you might be able to do: Rather than passing the array directly, you
    could pass a reference to a decorator whose derived classes are
    actually templates created from your array, e.g.

    |  template <typename T>
    |  class array_base
    |  {
    |  public:
    |    virtual ~array_base();
    |    virtual std::size_t size() const              = 0;
    |    virtual T&          operator[](int idx)       = 0;
    |    virtual T const&    operator[](int idx) const = 0;
    |    // possibly other operations, most likely none adding elements
    |  };

    |  template <typename T, typename Cont>
    |  class array: public array_base<T>
    |  {
    |  public:
    |    array(Cont& c): m_cont(c) {}
    |  private:
    |    std::size_t size() const { return m_cont.size(); }
    |    T&          operator[](int idx)       { return m_cont[idx]; }
    |    T const&    operator[](int idx) const { return m_cont[idx]; }
    |    Cont& m_cont;
    |  };

    You would now implement your dynamic generic operations in terms of
    'array_base<Base>&' where 'Base' is your base class and pass objects
    of type 'array<Base, Cont>' to it.

    Generally, something like this unnecessary burdonsome and
    inconvenient. If you merely need genericity but no dynamic
    polymorphism, you should probably apply generic techniques as in
    the STL: you pass appropriate iterators to suitably parameterized
    function templates.

    > To me at least, not having to make needless changes to code and having
    > the ability to sort things out dynamically using inheritance has always
    > sounded crisp.


    OO sounds really nice, doesn't it. It would be cool if it could
    live up to, say, 10% of its promises...

    > Also, does this problem mean there is some deficiency in my application
    > design?


    I'd guess "probably". Since you didn't mention your requirements
    it is impossible to tell, though. There are uses where you need
    dynamic polymorphism but these are rarer than many people think.
    Typically, it is easy to tell which approach is indicated: the
    one which is simplest and solves the problem :)
    --
    <mailto:> <http://www.dietmar-kuehl.de/>
    <http://www.contendix.com> - Software Development & Consulting
     
    Dietmar Kuehl, Dec 3, 2004
    #5
  6. <> wrote in message
    news:...

    > I am designing an application where to preserve the hierachy and for
    > code substitability, I need to pass an array of derived class object in
    > place of an array of base class object. Since I am using vector
    > class(STL), the compiler does not allow me to do this.


    Right. In general, a container of derived objects cannot substitute for a
    container of base objects, because what happens if you try to put a base
    object into the container?

    In other words: D is derived from B, and you have a function that expects a
    vector<B>. What happens if you were allowed to give it a vector<D> and it
    tried to put a B into the vector?
     
    Andrew Koenig, Dec 3, 2004
    #6
  7. Tom Widmer Guest

    On 3 Dec 2004 05:28:21 GMT, Dietmar Kuehl <>
    wrote:

    > wrote:
    >> I am designing an application where to preserve the hierachy and for
    >> code substitability, I need to pass an array of derived class object in
    >> place of an array of base class object. Since I am using vector
    >> class(STL), the compiler does not allow me to do this.

    >
    >Object orientation meets reality... There are actually languages
    >where something like this is supported but it is inherently broken:
    >An array of derived IS-NOT-A array of base, i.e. passing an array of
    >derived where an array of base is expected is a violation of the
    >Liskov Substition Principle: In an array of base, you should be able
    >to place a base object. Of course, this would mean that an array of
    >derived actually holds both derived and base objects or possibly
    >other derived objects which is not possible and thus proving that
    >it is a violation of LSP. Since I have seen answers trying to
    >address the problem by using pointers, note that the same LSP
    >violation applies to arrays of pointers.


    OTOH, a container of non-const derived IS-A const container of
    non-const base (but be careful of slicing if assignment isn't
    disabled). A container of non-const derived* IS-A const container of
    non-const base* const. The language doesn't support this though. Those
    languages that do support using an array of derived as an array of
    base don't support "const", and are thus saddled with an error prone
    runtime check to prevent elements from being illegally modified.

    >> I do realize there is a pitfall in this approach(size of arrays not
    >> matching etc), but I wonder how to get around this problem. I have a
    >> class hierachy with abstract base class and all I wonder why the
    >> principle of passing a derived class reference in place of base class
    >> is not extended to arrays. After all, we are making the code more
    >> substitutable right? How do we achieve substitutability in this case?

    >
    >Do you really need the class hierarchy or are you using it because
    >it "always sounded crisp"? If the latter, throw it out as fast as you
    >can! Object orientation has some merit but it is in no way a panacea
    >and it is grossly overused (well, at least the dynamic polymorphism
    >stuff is; I'm using encapsulation all the time but that is not the
    >central theme assumed as object orientation by most people).


    Polymorphism does have a place, but it often used at the wrong
    granularity. Concrete objects parametrised with various
    pointer-to-base objects (such as the iostreams classes parametrised
    with a streambuf and locale facets) are often useful, but often people
    make the original object an interface instead (e.g to use the
    iostreams example, by putting the output behaviour and formatting
    behaviour all in one class). Abstract base classes should generally
    only do one job.

    >Assuming you really need dynamic polymorphism for the stuff you do
    >(which is in my experience actually relatively unlikely; there are
    >a few uses but much less than is typically assumed), here is what
    >you might be able to do: Rather than passing the array directly, you
    >could pass a reference to a decorator whose derived classes are
    >actually templates created from your array, e.g.
    >
    >|  template <typename T>
    >|  class array_base
    >|  {
    >|  public:
    >|    virtual ~array_base();
    >|    virtual std::size_t size() const              = 0;
    >|    virtual T&          operator[](int idx)       = 0;
    >|    virtual T const&    operator[](int idx) const = 0;
    >|    // possibly other operations, most likely none adding elements
    >|  };
    >
    >|  template <typename T, typename Cont>
    >|  class array: public array_base<T>
    >|  {
    >|  public:
    >|    array(Cont& c): m_cont(c) {}
    >|  private:
    >|    std::size_t size() const { return m_cont.size(); }
    >|    T&          operator[](int idx)       { return m_cont[idx]; }
    >|    T const&    operator[](int idx) const { return m_cont[idx]; }
    >|    Cont& m_cont;
    >|  };
    >
    >You would now implement your dynamic generic operations in terms of
    >'array_base<Base>&' where 'Base' is your base class and pass objects
    >of type 'array<Base, Cont>' to it.


    A specialization for (smart) pointer types (returning non-references
    for operator[]) would be useful I think.

    Tom
     
    Tom Widmer, Dec 3, 2004
    #7
  8. * Andrew Koenig:
    >
    > In general, a container of derived objects cannot substitute for a
    > container of base objects, because what happens if you try to put a base
    > object into the container?


    Is there any way in C++ to create a smartpointer that acts like a Java
    reference?

    Assuming there isn't (which is what I believe), is there any way the
    language could be, er, "improved", so that that would be possible?

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Dec 3, 2004
    #8
  9. Thanks guys for your views. There were some very interesting and
    innovative ways to work around the problem in the replies.Sorry for
    getting back late because I had a bout of asthma and c++ was far from
    my mind for the past few days.

    Anyways, I did some soul searching about the design of the application
    and the one point that came to my mind was what one friend of mine
    used to say: "If it is too hard then maybe that is not the way it
    should be". The problem was that there were two parallel hierachies of
    classes(no, I did not design this part and I graciously inherited as a
    part of legacy code) with one hierachy of classes containing an array
    of other appropriate classes. To make this a little clearer,

    A<----B<----C<-----D and A is the pure abstract base class.

    Now we have

    E<----F<----G<----H and F,G,H have arrays of objects of kinds B,C and
    D and E is of course the abstract base class.

    Now, F,G,H return the arrays they contain to another function that
    performs some calculation on it. So, they have to be of the kind A to
    be generic and that is where the problem arises.

    Here is my take on it: The parallel hierachy idea is not so great coz:
    a) We are breaking the encapsulation principle. From what little
    domain knowledge I have of the application, B,C and D have too much
    coupling between them to be seperate classes.
    b) There is some fault in the relationships between the huge number
    classes I have and I have to figure that out.
    c)To make the classes more cohesive, we have to bring in B,C and D as
    data members of F,G and H(which can be done). This probably means that
    B,C, and D were not probably that unique to be classes in the fist
    place.

    Am I talking sense or am I advertersing my ignorance? I find it a
    little amusing that in IT, the fault of design is always with the
    other guy. I try to manage my ego and not to do that. In this case, it
    appears to be the case.

    And I believe in the concepts of object orientation as "guidelines"
    and not gospel and so will not hesistate to throw it out of the window
    if there are tangible benefits. In this case though, it appears as if
    the "guidelines" deserve more respect.

    What say people?

    Your responses will be gretly appreciated.

    Cheers,
    justanotherguy







    (Alf P. Steinbach) wrote in message news:<>...
    > * Andrew Koenig:
    > >
    > > In general, a container of derived objects cannot substitute for a
    > > container of base objects, because what happens if you try to put a base
    > > object into the container?

    >
    > Is there any way in C++ to create a smartpointer that acts like a Java
    > reference?
    >
    > Assuming there isn't (which is what I believe), is there any way the
    > language could be, er, "improved", so that that would be possible?
     
    justanotherguy, Dec 3, 2004
    #9
  10. Thanks guys for your views. There were some very interesting and
    innovative ways to work around the problem in the replies.Sorry for
    getting back late because I had a bout of asthma and c++ was far from
    my mind for the past few days.

    Anyways, I did some soul searching about the design of the application
    and the one point that came to my mind was what one friend of mine
    used to say: "If it is too hard then maybe that is not the way it
    should be". The problem was that there were two parallel hierachies of
    classes(no, I did not design this part and I graciously inherited as a
    part of legacy code) with one hierachy of classes containing an array
    of other appropriate classes. To make this a little clearer,

    A<----B<----C<-----D and A is the pure abstract base class.

    Now we have

    E<----F<----G<----H and F,G,H have arrays of objects of kinds B,C and
    D and E is of course the abstract base class.

    Now, F,G,H return the arrays they contain to another function that
    performs some calculation on it. So, they have to be of the kind A to
    be generic and that is where the problem arises.

    Here is my take on it: The parallel hierachy idea is not so great coz:
    a) We are breaking the encapsulation principle. From what little
    domain knowledge I have of the application, B,C and D have too much
    coupling between them to be seperate classes.
    b) There is some fault in the relationships between the huge number
    classes I have and I have to figure that out.
    c)To make the classes more cohesive, we have to bring in B,C and D as
    data members of F,G and H(which can be done). This probably means that
    B,C, and D were not probably that unique to be classes in the fist
    place.

    Am I talking sense or am I advertersing my ignorance? I find it a
    little amusing that in IT, the fault of design is always with the
    other guy. I try to manage my ego and not to do that. In this case, it
    appears to be the case.

    And I believe in the concepts of object orientation as "guidelines"
    and not gospel and so will not hesistate to throw it out of the window
    if there are tangible benefits. In this case though, it appears as if
    the "guidelines" deserve more respect.

    What say people?

    Your responses will be gretly appreciated.

    Cheers,
    justanotherguy







    (Alf P. Steinbach) wrote in message news:<>...
    > * Andrew Koenig:
    > >
    > > In general, a container of derived objects cannot substitute for a
    > > container of base objects, because what happens if you try to put a base
    > > object into the container?

    >
    > Is there any way in C++ to create a smartpointer that acts like a Java
    > reference?
    >
    > Assuming there isn't (which is what I believe), is there any way the
    > language could be, er, "improved", so that that would be possible?
     
    justanotherguy, Dec 3, 2004
    #10
    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. Jeff
    Replies:
    4
    Views:
    618
    Peter_Julian
    Mar 8, 2006
  2. Bit Byte
    Replies:
    3
    Views:
    653
    Bit Byte
    Mar 5, 2007
  3. Replies:
    1
    Views:
    423
    myork
    May 23, 2007
  4. Replies:
    1
    Views:
    410
    Victor Bazarov
    May 23, 2007
  5. Replies:
    2
    Views:
    747
Loading...

Share This Page