Templated containers of inherited objects

Discussion in 'C++' started by George Exarchakos, Feb 16, 2007.

  1. Hi everyone,

    I'd like your help...

    Can we have a std::list<BASE> where BASE be the base class of a class
    hierarchy? I want to add to this list objects that are inherited from
    BASE class but not necessarily the same...

    class base {
    int x;
    };

    class child1 : public base {
    int d;
    };

    class child2 : public base {
    int e;
    };

    int main() {
    std::list<base> mylist;
    child1 _c1;
    child2 _c2;
    mylist.push_back(_c1);
    mylist.push_back(_c2);
    return 0;
    }

    It seems that I lose the information of _c1 and _c2 like they are
    converted to base.

    Please, do you have any idea how can I achieve that? Do I have to
    implement my own container?

    Many thanks in advance,
    -- George
     
    George Exarchakos, Feb 16, 2007
    #1
    1. Advertising

  2. George Exarchakos

    red floyd Guest

    George Exarchakos wrote:
    >
    >
    > Can we have a std::list<BASE> where BASE be the base class of a class
    > hierarchy? I want to add to this list objects that are inherited from
    > BASE class but not necessarily the same...
    >
    > [redacted]
    >
    > Please, do you have any idea how can I achieve that? Do I have to
    > implement my own container?


    You've run into the slicing problem. You need to create a container of
    (smart) pointers to your base class.

    That is, std::list<base*>, or std::list<some_smart_ptr<base> >

    See the FAQ, http://www.parashift.com/c -faq-lite/containers.html#faq-34.4
     
    red floyd, Feb 16, 2007
    #2
    1. Advertising

  3. On Feb 16, 5:51 pm, red floyd <> wrote:
    > George Exarchakos wrote:
    >
    > > Can we have a std::list<BASE> where BASE be the base class of a class
    > > hierarchy? I want to add to this list objects that are inherited from
    > > BASE class but not necessarily the same...

    >
    > > [redacted]
    > >

    >
    > > Please, do you have any idea how can I achieve that? Do I have to
    > > implement my own container?

    >
    > You've run into the slicing problem. You need to create a container of
    > (smart) pointers to your base class.
    >
    > That is, std::list<base*>, or std::list<some_smart_ptr<base> >
    >
    > See the FAQ,http://www.parashift.com/c -faq-lite/containers.html#faq-34.4


    Many thanks Red Floyd! This tip is exactly what I was looking for...
    -- George
     
    George Exarchakos, Feb 16, 2007
    #3
  4. On 16 Feb 2007 09:17:51 -0800, "George Exarchakos" wrote:
    >Can we have a std::list<BASE> where BASE be the base class of a class
    >hierarchy? I want to add to this list objects that are inherited from
    >BASE class but not necessarily the same...


    STL does not support object-oriented programming. STL containers,
    iterators and algorithms are designed only for values, not for
    (pointers to) objects. Workarounds exist but with 'Standard' STL there
    always remains an 'impedance mismatch' when objects are used.

    Best regards,
    Roland Pibinger
     
    Roland Pibinger, Feb 16, 2007
    #4
  5. George Exarchakos

    Guest

    On Feb 16, 1:05 pm, (Roland Pibinger) wrote:
    > On 16 Feb 2007 09:17:51 -0800, "George Exarchakos" wrote:
    >
    > >Can we have a std::list<BASE> where BASE be the base class of a class
    > >hierarchy? I want to add to this list objects that are inherited from
    > >BASE class but not necessarily the same...

    >
    > STL does not support object-oriented programming.


    I think that this comment is misleading. If I understand the point of
    the statement, its that using objects that use polymorphism in a
    container isn't supported. Because this isn't the case at all.
    Although, objects used with the STL must provide certain concepts,
    such as default constructibility, copy constructibility et al.

    When dealing with class hierarchies, we must pay special attention to
    copy constructibility and other concepts because these can lead to
    problems such as slicing as noticed by the OP.

    Using pointers is a perfectly valid method of fixing this issue.

    On the other hand, if Roland meant that "You can't subclass objects
    such as std::vector." then he is in fact correct. IIRC, most stl
    objects don't provide a virtual destructor. And further, the STL (as
    its name suggests) is a library of templates. Using templates with
    inheritance is at best tricky.

    I'm not sure what the actual standard has to say on this, but g++
    4.0.2 won't compile this:

    class A
    {
    public:
    A() {}
    ~A() {}

    template< typename TYPE >
    virtual void
    echo( TYPE val ) = 0 ;
    } ;

    The error is:
    error: invalid use of 'virtual' in template declaration of 'virtual
    void A::echo(TYPE)'

    This all makes sense if we think in terms of the (non-standard
    dictated) vtable implementation of polymorphism. When we create the
    vtable for A, we have no idea how many entries it will have.
    Theoretically, it would need to have an entry for every template
    instantiation of A::echo(TYPE).

    Whats more, this class definition could possibly change after it has
    been compiled. Ie, compiled in a library, then some client code calls
    A::echo(TYPE) with a type thats not used in the library. Thus the
    vtable would change and break all sorts of things.

    STL containers,
    > iterators and algorithms are designed only for values, not for
    > (pointers to) objects.


    This is just wrong. A pointer *is* a value. Its a memory address. STL
    containers will work just fine with pointers.

    Objects on the other hand must provide the required concepts as
    mentioned before. The entire point of the STL is to provide a system
    that allows for use with any custom type. They'd be pretty pointless
    if they could only hold things like int, float, char* et al.

    Workarounds exist but with 'Standard' STL there
    > always remains an 'impedance mismatch' when objects are used.
    >


    I'm not entirely certain what 'impedance mismatch' means. Although it
    kinda reminds me of studying power amplifiers...

    But the point that needs to be made here is that using smart pointers
    in a container is not a work around. Smart pointers are a means to
    perform resource control. In the case of using pointers, if the only
    copy of a pointer to an object is in a std::vector, and then
    std::vector::clear() is called, then the objects in it are leaked
    (assuming we don't have copies to the pointer anywhere else). Smart
    pointers do reference counting ( or some other method ) to determine
    when an object should be delete'ed. So when std::vector::clear() is
    called, the smart pointers can determine whether or not the object
    should be delete'ed and thuse, no memory is leaked.

    > Best regards,
    > Roland Pibinger


    HTH,
    Paul Davis
     
    , Feb 17, 2007
    #5
  6. George Exarchakos

    Gavin Deane Guest

    On 17 Feb, 01:29, ""
    <> wrote:
    > On the other hand, if Roland meant that "You can't subclass objects
    > such as std::vector." then he is in fact correct. IIRC, most stl
    > objects don't provide a virtual destructor.


    That doesn't stop me deriving from them.
    #include <vector>
    class foo : public std::vector<int> {};

    Nothing wrong there. The only thing I can't do without a virtual
    destructor is delete polymorphically.

    Whether deriving from standard containers is a good idea or not is a
    different question, but there is certainly nothing that prevents it.

    Gavin Deane
     
    Gavin Deane, Feb 17, 2007
    #6
  7. George Exarchakos

    Kai-Uwe Bux Guest

    Gavin Deane wrote:

    > On 17 Feb, 01:29, ""
    > <> wrote:
    >> On the other hand, if Roland meant that "You can't subclass objects
    >> such as std::vector." then he is in fact correct. IIRC, most stl
    >> objects don't provide a virtual destructor.

    >
    > That doesn't stop me deriving from them.
    > #include <vector>
    > class foo : public std::vector<int> {};
    >
    > Nothing wrong there. The only thing I can't do without a virtual
    > destructor is delete polymorphically.
    >
    > Whether deriving from standard containers is a good idea or not is a
    > different question, but there is certainly nothing that prevents it.


    Except that, formally, an implementation of std::vector<> that prevents
    derivation (using a virtual base class trick getting) is standard
    compliant. In practice, all implementations of the standard library allow
    for derivation; and I do not hesitate to derive from standard container
    classes whenever it feels appropriate. However, I do not see any blessing
    for this technique in the standard. As far as I can tell, this would be a
    compliant implementation:

    namespace std {

    class __protected_constructor {
    protected:

    __protected_constructor ( void ) {}

    }; // protected_constructor

    template < typename T, typename A >
    class vector : private virtual __protected_constructor {

    // ... do the vector business.

    }; // vector

    }


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Feb 17, 2007
    #7
  8. On 16 Feb 2007 17:29:09 -0800, paul joseph wrote:
    >On Feb 16, 1:05 pm, (Roland Pibinger) wrote:
    >> STL does not support object-oriented programming.

    >
    >I think that this comment is misleading. If I understand the point of
    >the statement, its that using objects that use polymorphism in a
    >container isn't supported.


    Just look at the containers, iterators and algorithms. No algorithm
    works with (pointers to) objects (except random_shuffle).

    >Because this isn't the case at all.
    >Although, objects used with the STL must provide certain concepts,
    >such as default constructibility, copy constructibility et al.
    >When dealing with class hierarchies, we must pay special attention to
    >copy constructibility and other concepts because these can lead to
    >problems such as slicing as noticed by the OP.


    Objects (in the meaning used in object-oriented programing) are
    characterized by identity, state and behavior. It makes no sense to
    copy or assign objects. Copy constructibility makes only sense for
    values and value-oriented libraries like STL.

    >Using pointers is a perfectly valid method of fixing this issue.


    If it needs fixing it must be broken.

    >STL containers,
    >> iterators and algorithms are designed only for values, not for
    >> (pointers to) objects.

    >
    >This is just wrong. A pointer *is* a value. Its a memory address. STL
    >containers will work just fine with pointers.


    A pointer is not a value, otherwise one could just use an int instead.
    A pointer in C/C++ has the combined meaning of reference and address.

    >Objects on the other hand must provide the required concepts as
    >mentioned before.


    The 'required concepts' make sense only for values, not objects.

    >The entire point of the STL is to provide a system
    >that allows for use with any custom type. They'd be pretty pointless
    >if they could only hold things like int, float, char* et al.


    .... and 'concrete types' as Stroustrup calls them.

    >Workarounds exist but with 'Standard' STL there
    >> always remains an 'impedance mismatch' when objects are used.

    >
    >I'm not entirely certain what 'impedance mismatch' means. Although it
    >kinda reminds me of studying power amplifiers...


    It means the mismatch that becomes evident when you try to use objects
    with the value-based STL library.

    >But the point that needs to be made here is that using smart pointers
    >in a container is not a work around. Smart pointers are a means to
    >perform resource control.


    Since 'smart pointers' only try to imitate real pointers the
    'impedance mismatch' is the same.

    In general, STL is the attempt introduce the functional paradigm into
    the C++ language as counterpart to the object-oriented paradigm. This
    attempt has produced much misunderstanding and confusion.

    Best wishes,
    Roland Pibinger
     
    Roland Pibinger, Feb 17, 2007
    #8
  9. * Kai-Uwe Bux:
    >
    > ... formally, an implementation of std::vector<> that prevents
    > derivation (using a virtual base class trick getting) is standard
    > compliant.


    Sorry, that's incorrect.

    §17.3.1.2/1 "The library can be extended by a C++ program. ... Such
    extensions are generally one of the following: ... Derived classes."

    --
    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, Feb 17, 2007
    #9
  10. George Exarchakos

    Guest

    On Feb 17, 1:12 pm, (Roland Pibinger) wrote:
    > On 16 Feb 2007 17:29:09 -0800, paul joseph wrote:
    >
    > >On Feb 16, 1:05 pm, (Roland Pibinger) wrote:
    > >> STL does not support object-oriented programming.

    >
    > >I think that this comment is misleading. If I understand the point of
    > >the statement, its that using objects that use polymorphism in a
    > >container isn't supported.

    >
    > Just look at the containers, iterators and algorithms. No algorithm
    > works with (pointers to) objects (except random_shuffle).
    >


    This examples shows how to use std::sort on a std::vector or pointers.
    As well as a trivial example of std::for_each to print the vector.

    #include <iostream>
    #include <vector>

    class A
    {
    public:
    A( int val )
    {
    _val = val ;
    }

    ~A() {}

    int
    value()
    {
    return _val ;
    }

    private:

    int _val ;
    } ;

    bool
    compare( A* lhs, A* rhs )
    {
    return lhs->value() < rhs->value() ;
    }

    void
    echo( A* a )
    {
    std::cout << a->value() << std::endl ;
    }

    int
    main( int argc, char* argv[] )
    {
    std::vector< A* > vec ;

    for( int i = 10 ; i > 0 ; i-- )
    {
    A* a = new A( i ) ;
    vec.push_back( a ) ;
    }

    std::cout << "Before sort:" << std::endl ;
    std::for_each( vec.begin(), vec.end(), echo ) ;

    std::sort( vec.begin(), vec.end(), compare ) ;

    std::cout << "After sort:" << std::endl ;
    std::for_each( vec.begin(), vec.end(), echo ) ;
    }

    > >Because this isn't the case at all.
    > >Although, objects used with the STL must provide certain concepts,
    > >such as default constructibility, copy constructibility et al.
    > >When dealing with class hierarchies, we must pay special attention to
    > >copy constructibility and other concepts because these can lead to
    > >problems such as slicing as noticed by the OP.

    >
    > Objects (in the meaning used in object-oriented programing) are
    > characterized by identity, state and behavior. It makes no sense to
    > copy or assign objects. Copy constructibility makes only sense for
    > values and value-oriented libraries like STL.
    >


    You're right, wrong, and neither right or wrong. Of course objects are
    characterized by their state and behavior. You're absolutely wrong
    that it makes no sense to copy or assign objects, there are instances
    where this may be true, but its just plain wrong to say never. I use
    it quite a bit.

    And the last bit that copy constructibility only makes sense in the
    STL isn't quite right, although I don't tend to use it alot in my own
    code, thats mostly becuase I don't write code that requires this
    concept.

    > >Using pointers is a perfectly valid method of fixing this issue.

    >
    > If it needs fixing it must be broken.
    >
    > >STL containers,
    > >> iterators and algorithms are designed only for values, not for
    > >> (pointers to) objects.

    >
    > >This is just wrong. A pointer *is* a value. Its a memory address. STL
    > >containers will work just fine with pointers.

    >
    > A pointer is not a value, otherwise one could just use an int instead.
    > A pointer in C/C++ has the combined meaning of reference and address.
    >


    You can use an int for a pointer! (Disclaimer: Its very ill advised,
    bad C++, and requires that an int be the same size as the pointer you
    wish to obfuscate.)

    > >Objects on the other hand must provide the required concepts as
    > >mentioned before.

    >
    > The 'required concepts' make sense only for values, not objects.
    >
    > >The entire point of the STL is to provide a system
    > >that allows for use with any custom type. They'd be pretty pointless
    > >if they could only hold things like int, float, char* et al.

    >
    > ... and 'concrete types' as Stroustrup calls them.
    >
    > >Workarounds exist but with 'Standard' STL there
    > >> always remains an 'impedance mismatch' when objects are used.

    >
    > >I'm not entirely certain what 'impedance mismatch' means. Although it
    > >kinda reminds me of studying power amplifiers...

    >
    > It means the mismatch that becomes evident when you try to use objects
    > with the value-based STL library.
    >
    > >But the point that needs to be made here is that using smart pointers
    > >in a container is not a work around. Smart pointers are a means to
    > >perform resource control.

    >
    > Since 'smart pointers' only try to imitate real pointers the
    > 'impedance mismatch' is the same.
    >


    I'm unsure as to how I should respond to this.

    Yes, smart pointers only imitate real pointers. They are actually
    objects that use a little voodoo to track the resources they own (The
    underlying raw pointer). Because they are objects, they can be copied
    and assigned. Writing code without smart pointers is ill-advised in my
    opinion.

    The only 'mismatch' that occurs with the objects used in the STL is
    when the object doesn't support something required of it. The
    algorithms in the STL were designed to work with any user defined type
    as long as those types support a few basic operations. Obviously, if
    something doesn't meet these requirements it won't work. You'll find
    this happens alot when requirements aren't met.

    > In general, STL is the attempt introduce the functional paradigm into
    > the C++ language as counterpart to the object-oriented paradigm. This
    > attempt has produced much misunderstanding and confusion.
    >


    Obviously the STL can be misunderstood...

    > Best wishes,
    > Roland Pibinger
     
    , Feb 17, 2007
    #10
  11. George Exarchakos

    Guest

    On Feb 17, 1:57 pm, "Alf P. Steinbach" <> wrote:
    > * Kai-Uwe Bux:
    >
    >
    >
    > > ... formally, an implementation of std::vector<> that prevents
    > > derivation (using a virtual base class trick getting) is standard
    > > compliant.

    >
    > Sorry, that's incorrect.
    >
    > §17.3.1.2/1 "The library can be extended by a C++ program. ... Such
    > extensions are generally one of the following: ... Derived classes."
    >
    > --
    > 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?


    Yeah, I was completely wrong on this point, as the following example
    illustrates:

    #include <iostream>
    #include <vector>

    template< typename TYPE >
    class A : public std::vector<TYPE>
    {
    public:
    A() {}
    } ;

    int
    main( int argc, char* argv[] )
    {
    A<int> a ;
    a.push_back( 0 ) ;
    std::cout << a.size() << std::endl ;
    }
     
    , Feb 17, 2007
    #11
  12. George Exarchakos

    Kai-Uwe Bux Guest

    Alf P. Steinbach wrote:

    > * Kai-Uwe Bux:
    >>
    >> ... formally, an implementation of std::vector<> that prevents
    >> derivation (using a virtual base class trick getting) is standard
    >> compliant.

    >
    > Sorry, that's incorrect.


    No need to be sorry: if I was incorrect here, I would be quite happy.

    > §17.3.1.2/1 "The library can be extended by a C++ program. ... Such
    > extensions are generally one of the following: ... Derived classes."


    You may be right (and I hope you are). However, I feel uneasy relying on
    that clause alone.

    a) Formally, the trick presented does not prevent derivation. It just
    prevents construction of objects of the derived type:

    namespace std {

    class __protected_constructor {
    protected:

    __protected_constructor ( void ) {}

    }; // protected_constructor

    template < typename T, typename A >
    class vector : private virtual __protected_constructor {

    // ... do the vector business.

    }; // vector

    }

    You still can do

    class X : public std::vector<int> {
    }


    you just cannot do

    X x;

    anymore. Where do you find a provision that classes derived from
    std::vector<> have to behave they way you want it to be? Without specific
    guarantees that extensions are actually useful, the clause you quote
    amounts to very little.


    b) This is somewhat recognized in the part of the clause that you snipped:

    The library can be extended by a C++ program. Each clause, as applicable,
    describes the requirements that such extensions must meet. Such extensions
    are generally one of the following:
    ? Template arguments
    ? Derived classes
    ? Containers, iterators, and/or algorithms that meet an interface convention

    I read the sentence "Each clause, as applicable, describes the requirements
    that such extensions must meet." as a hint that more specific provisions
    are supposed to determine the semantics (behavior) of extensions. In the
    absence of such provisions, I do not see how the standard places any
    requirements on the behavior of a program extending the library. I.e., I
    see a lot of undefined behavior. 17.3.1.2 in itself clearly does not say
    how things are supposed to behave.


    c) On the other hand, in favor of your reading, I can add that library
    components such as

    unary_function<>

    which are clearly meant to be derived from, come without any hint whatsoever
    that derivation is ok. However, the are other example, too: clause
    [24.3.2/1] specifically blesses the use of std::iterator<> as a base class.


    d) Finally, a question: consider a type such as std::vector::iterator that
    is labelled as implementation_defined, does the extendibility clause apply
    to it, too? In that case, std::vector<T>::iterator could not be implemented
    as T*.



    Anyway, I would be _really_ _really_ happy if I was wrong and derivation
    from standard containers was blessed by the standard. Also I think that (c)
    is actually quite strong a point in your direction. But I think, the
    standard could be more clear in this regard.



    Thanks

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Feb 17, 2007
    #12
  13. * Kai-Uwe Bux:
    > Alf P. Steinbach wrote:
    >
    >> * Kai-Uwe Bux:
    >>> ... formally, an implementation of std::vector<> that prevents
    >>> derivation (using a virtual base class trick getting) is standard
    >>> compliant.

    >> Sorry, that's incorrect.

    >
    > No need to be sorry: if I was incorrect here, I would be quite happy.


    :)


    >> §17.3.1.2/1 "The library can be extended by a C++ program. ... Such
    >> extensions are generally one of the following: ... Derived classes."

    >
    > You may be right (and I hope you are). However, I feel uneasy relying on
    > that clause alone.



    [snip]
    > Without specific
    > guarantees that extensions are actually useful, the clause you quote
    > amounts to very little.


    How would you define "useful"?

    Anywayhow, I've argued successfully earlier that any program whatsoever
    is a 100% standard-conforming C++ compiler, by the formally interpreted
    rules of the standard. That's because the standard isn't a mathematical
    document, but relies on the reader's common sense: it's formal in
    places, but only insofar as formal definitions are practical and really
    communicate something. So you can rejoice ;-), the standard does
    specify, to the extent it can, that std::vector can be derived from.

    --
    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, Feb 17, 2007
    #13
  14. On Feb 18, 2:12 am, (Roland Pibinger) wrote:
    > On 16 Feb 2007 17:29:09 -0800, paul joseph wrote:
    > >STL containers,
    > >> iterators and algorithms are designed only for values, not for
    > >> (pointers to) objects.

    >
    > >This is just wrong. A pointer *is* a value. Its a memory address. STL
    > >containers will work just fine with pointers.

    >
    > A pointer is not a value, otherwise one could just use an int instead.
    > A pointer in C/C++ has the combined meaning of reference and address.


    What is your definition of 'value' that makes you say that a pointer
    isn't a value? After all a pointer *is* just an integer, but one which
    is interpreted in a specific way (old x86 style far pointers
    notwithstanding), but that is the same as many other value types too.

    > In general, STL is the attempt introduce the functional paradigm into
    > the C++ language as counterpart to the object-oriented paradigm. This
    > attempt has produced much misunderstanding and confusion.


    I've come across this assertion a couple of times. To me the STL is a
    fine bit of OO programming, but I can see where the functional view
    comes into it too.

    The use of generic containers and the ability to perform operations no
    them has been part of both functional languages and OO languages up
    until early C++ and Java. What the STL doesn't do though is to enforce
    the 'no side effect' rule from pure functional programming languages.
    To me this puts it firmly on the OO side. It isn't really doing
    anything that the containers in Smalltalk don't do and I'm not sure
    that anybody would claim them to be a functional paradigm.


    K
     
    =?iso-8859-1?q?Kirit_S=E6lensminde?=, Feb 18, 2007
    #14
  15. On 17 Feb 2007 12:30:46 -0800, "paul.joseph.davis" wrote:
    >On Feb 17, 1:12 pm, (Roland Pibinger) wrote:
    >> Just look at the containers, iterators and algorithms. No algorithm
    >> works with (pointers to) objects (except random_shuffle).

    >
    >This examples shows how to use std::sort on a std::vector or pointers.
    >As well as a trivial example of std::for_each to print the vector.
    >
    >#include <iostream>
    >#include <vector>
    >
    >class A
    >{
    > public:
    > A( int val )
    > {
    > _val = val ;
    > }
    >
    > ~A() {}
    >
    > int
    > value()
    > {
    > return _val ;
    > }
    >
    > private:
    >
    > int _val ;
    >} ;
    >
    >bool
    >compare( A* lhs, A* rhs )
    >{
    > return lhs->value() < rhs->value() ;
    >}


    This is the workaround. As said before no algorithm (except
    random_shuffle) works with pointers out of the box.

    >void
    >echo( A* a )
    >{
    > std::cout << a->value() << std::endl ;
    >}
    >
    >int
    >main( int argc, char* argv[] )
    >{
    > std::vector< A* > vec ;
    >
    > for( int i = 10 ; i > 0 ; i-- )
    > {
    > A* a = new A( i ) ;
    > vec.push_back( a ) ;
    > }


    // compiles but wrong result
    std::sort( vec.begin(), vec.end()) ;

    // ditto; 2 dereferences needed to access the object
    for (std::vector<A*>::iterator i = vec.begin(); i != vec.end(); ++i) {
    std::cout << *i << std::endl;
    }

    const std::vector<A*>& const_vec = vec;
    // changing pointed-to element in const vector
    *const_vec[0] = 3;

    // changing pointed-to element through const_iterator
    // 2 dereferences needed to access the object.
    **const_vec.begin() = 4;

    > std::cout << "Before sort:" << std::endl ;
    > std::for_each( vec.begin(), vec.end(), echo ) ;
    >
    > std::sort( vec.begin(), vec.end(), compare ) ;
    >
    > std::cout << "After sort:" << std::endl ;
    > std::for_each( vec.begin(), vec.end(), echo ) ;

    // leaking objects
    >}
    >> Objects (in the meaning used in object-oriented programing) are
    >> characterized by identity, state and behavior. It makes no sense to
    >> copy or assign objects. Copy constructibility makes only sense for
    >> values and value-oriented libraries like STL.

    >
    >You're right, wrong, and neither right or wrong. Of course objects are
    >characterized by their state and behavior. You're absolutely wrong
    >that it makes no sense to copy or assign objects, there are instances
    >where this may be true, but its just plain wrong to say never. I use
    >it quite a bit.


    When identity is important (which is the case with objects) then
    duplicate instances are always problematic (not to speak of
    assignment).

    Best wishes,
    Roland Pibinger
     
    Roland Pibinger, Feb 18, 2007
    #15
  16. On 17 Feb 2007 22:53:14 -0800, "=?iso-8859-1?q?Kirit_S=E6lensminde?="
    <> wrote:
    >On Feb 18, 2:12 am, (Roland Pibinger) wrote:
    >> A pointer is not a value, otherwise one could just use an int instead.
    >> A pointer in C/C++ has the combined meaning of reference and address.

    >
    >What is your definition of 'value' that makes you say that a pointer
    >isn't a value? After all a pointer *is* just an integer, but one which
    >is interpreted in a specific way (old x86 style far pointers
    >notwithstanding), but that is the same as many other value types too.


    A pointer can be dereferenced, i.e. pointers have a specific
    dereference operator.

    >> In general, STL is the attempt introduce the functional paradigm into
    >> the C++ language as counterpart to the object-oriented paradigm. This
    >> attempt has produced much misunderstanding and confusion.

    >
    >I've come across this assertion a couple of times. To me the STL is a
    >fine bit of OO programming, but I can see where the functional view
    >comes into it too.


    OO is characterized by inherited and polymorphic objects. STL neither
    uses nor supports these.

    >The use of generic containers and the ability to perform operations no
    >them has been part of both functional languages and OO languages up
    >until early C++ and Java.


    The term 'generic' doesn't tell you anything about the underying
    paradigm.

    >What the STL doesn't do though is to enforce
    >the 'no side effect' rule from pure functional programming languages.


    STL is not pure functional. Otherwise sort, for_each and the other
    'mutating' algorithms would have to return a list of immutable values.
    But it is influenced by functional programming. The term 'generic' is
    just a distraction in this context.

    >To me this puts it firmly on the OO side.


    Side effects don't necessarily mean OO :)

    Best wishes,
    Roland Pibinger
     
    Roland Pibinger, Feb 18, 2007
    #16
  17. George Exarchakos

    Kai-Uwe Bux Guest

    Roland Pibinger wrote:

    > On 17 Feb 2007 22:53:14 -0800, "=?iso-8859-1?q?Kirit_S=E6lensminde?="
    > <> wrote:
    >>On Feb 18, 2:12 am, (Roland Pibinger) wrote:
    >>> A pointer is not a value, otherwise one could just use an int instead.
    >>> A pointer in C/C++ has the combined meaning of reference and address.

    >>
    >>What is your definition of 'value' that makes you say that a pointer
    >>isn't a value? After all a pointer *is* just an integer, but one which
    >>is interpreted in a specific way (old x86 style far pointers
    >>notwithstanding), but that is the same as many other value types too.

    >
    > A pointer can be dereferenced, i.e. pointers have a specific
    > dereference operator.
    >
    >>> In general, STL is the attempt introduce the functional paradigm into
    >>> the C++ language as counterpart to the object-oriented paradigm. This
    >>> attempt has produced much misunderstanding and confusion.

    >>
    >>I've come across this assertion a couple of times. To me the STL is a
    >>fine bit of OO programming, but I can see where the functional view
    >>comes into it too.

    >
    > OO is characterized by inherited and polymorphic objects. STL neither
    > uses nor supports these.


    Hm, I always felt that this is simply because pointers are not really what
    we want when dealing with objects. What we want is something like a
    reference that can be assigned and re-seated. Something like this:

    template < typename T >
    class smart_ref {

    T * the_ptr;

    public:

    // maybe, we should not have this constructor !
    smart_ref ( T * ptr )
    : the_ptr ( ptr )
    {}

    smart_ref ( T & ref )
    : the_ptr ( &ref )
    {}

    operator T & ( void ) {
    return ( *the_ptr );
    }

    operator T const & ( void ) const {
    return ( *the_ptr );
    }

    // these really want to be overloaded dot-operators:
    T * operator-> ( void ) {
    return ( the_ptr );
    }

    T const * operator-> ( void ) const {
    return ( the_ptr );
    }

    };

    With this, STL works to some extend. The amount of failure derives mostly
    from the fact that we cannot overload the dot-operator (which is a real
    shame).


    #include <vector>
    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <ostream>

    class X {

    unsigned int the_ssn;

    public:

    X ( unsigned int ssn )
    : the_ssn ( ssn )
    {}

    virtual
    std::string name ( void ) const {
    return ( "X" );
    }

    unsigned int ssn ( void ) const {
    return ( the_ssn );
    }

    ~X ( void ) {}

    friend
    bool operator< ( X const & lhs, X const & rhs ) {
    return ( lhs.the_ssn < rhs.the_ssn );
    }

    };

    struct Y : public X {

    Y ( unsigned int ssn )
    : X ( ssn )
    {}

    virtual
    std::string name ( void ) const {
    return ( "Y" );
    }

    virtual
    ~Y ( void ) {}

    };

    std::eek:stream & operator<< ( std::eek:stream & ostr,
    X const & x ) {
    return ( ostr << x.name() << "(" << x.ssn() << ")" );
    }

    typedef smart_ref<X> X_ref;
    typedef std::vector<X_ref> X_vect;

    int main ( void ) {
    {
    X a ( 333451234 );
    X b ( 919113247 );
    Y c ( 238648666 );
    Y d ( 237986136 );
    X e ( 879823769 );
    X_vect xv;
    xv.push_back( X_ref(a) );
    xv.push_back( X_ref(b) );
    xv.push_back( X_ref(c) );
    xv.push_back( X_ref(d) );
    xv.push_back( X_ref(e) );
    std::sort( xv.begin(), xv.end() );
    for ( X_vect::const_iterator iter = xv.begin();
    iter != xv.end(); ++iter ) {
    std::cout << *iter << '\n';
    }
    }
    }


    Maybe, it's not that STL does not want to work with OO-objects. Maybe, it's
    just that pointers make for lousy OO-objects.


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Feb 18, 2007
    #17
  18. On Sun, 18 Feb 2007 09:31:59 -0500, Kai-Uwe Bux wrote:
    >Hm, I always felt that this is simply because pointers are not really what
    >we want when dealing with objects. What we want is something like a
    >reference that can be assigned and re-seated. Something like this:
    >
    >template < typename T >
    >class smart_ref {
    >
    > T * the_ptr;
    >
    > public:
    >
    > // maybe, we should not have this constructor !
    > smart_ref ( T * ptr )
    > : the_ptr ( ptr )
    > {}
    >
    > smart_ref ( T & ref )
    > : the_ptr ( &ref )
    > {}
    >
    > operator T & ( void ) {
    > return ( *the_ptr );
    > }
    >
    > operator T const & ( void ) const {
    > return ( *the_ptr );
    > }
    >
    > // these really want to be overloaded dot-operators:
    > T * operator-> ( void ) {
    > return ( the_ptr );
    > }
    >
    > T const * operator-> ( void ) const {
    > return ( the_ptr );
    > }
    >
    >};
    >
    >With this, STL works to some extend.


    The problem with this approach is the automatic conversion from
    pointer to reference (operator T&) which produces all kinds of
    surprising results. BTW, Boost has a similar library (just for the
    sake of completeness, not that I recommend Boost).
    Moreover, this approach tackles the problem from the wrong direction.
    Containers, iterators and algorithms need to become 'pointer-aware'.
    This is not too difficult and has been done in the past.

    >The amount of failure derives mostly
    >from the fact that we cannot overload the dot-operator (which is a real
    >shame).


    IMO, pointers and references should be unified in a (hypothetical) new
    C++. The result would be references similar (but not identical) to
    Java.

    Best wishes,
    Roland Pibinger
     
    Roland Pibinger, Feb 18, 2007
    #18
  19. On Feb 18, 7:03 pm, (Roland Pibinger) wrote:
    > On 17 Feb 2007 22:53:14 -0800, "=?iso-8859-1?q?Kirit_S=E6lensminde?="
    >
    > <> wrote:
    > >On Feb 18, 2:12 am, (Roland Pibinger) wrote:
    > >> A pointer is not a value, otherwise one could just use an int instead.
    > >> A pointer in C/C++ has the combined meaning of reference and address.

    >
    > >What is your definition of 'value' that makes you say that a pointer
    > >isn't a value? After all a pointer *is* just an integer, but one which
    > >is interpreted in a specific way (old x86 style far pointers
    > >notwithstanding), but that is the same as many other value types too.

    >
    > A pointer can be dereferenced, i.e. pointers have a specific
    > dereference operator.


    I still don't see how that stops it from being a value. Are you saying
    that pointers don't follow value semantics because they can also be de-
    referenced? In which case why is that relevant? Or are you saying they
    do follow value semantics despite not being values?

    >
    > >> In general, STL is the attempt introduce the functional paradigm into
    > >> the C++ language as counterpart to the object-oriented paradigm. This
    > >> attempt has produced much misunderstanding and confusion.

    >
    > >I've come across this assertion a couple of times. To me the STL is a
    > >fine bit of OO programming, but I can see where the functional view
    > >comes into it too.

    >
    > OO is characterized by inherited and polymorphic objects. STL neither
    > uses nor supports these.


    OO is characterised by encapsulated objects that have internal state,
    are responsible for their own behaviour and communicate through
    message passing. The STL does follow this. This newer definition of OO
    centred around inheritance is a direct result of Java and to a lesser
    extent C++, but it has no historic basis.

    I've explained this in more detail no my web site:
    http://www.kirit.com/The three pillars of Object Orientation


    K
     
    =?iso-8859-1?q?Kirit_S=E6lensminde?=, Feb 19, 2007
    #19
  20. George Exarchakos

    Jerry Coffin Guest

    In article <>,
    says...

    [ ... ]

    > > OO is characterized by inherited and polymorphic objects. STL neither
    > > uses nor supports these.

    >
    > OO is characterised by encapsulated objects that have internal state,
    > are responsible for their own behaviour and communicate through
    > message passing. The STL does follow this. This newer definition of OO
    > centred around inheritance is a direct result of Java and to a lesser
    > extent C++, but it has no historic basis.


    I see little basis for this claim. Consider, for example:

    Object-oriented programming is a method of implementation in
    which programs are orgainzed as cooperative collections of
    objects, each of which represents an instance of some class,
    and whose classes are all members of a hierarchy of classes
    united via inheritance relationships.

    That's from _Object-Oriented Analysis and Design: With Applications
    (Second Edition)_, Grady Booch, 1994. In the same book, use of objects
    but not inheritance is titled "Object-based".

    Going back even further:

    A subclass specifies that its instances will be the same
    as instances of another class, called its _superclass_,
    except for the differences that are explicitly stated.
    The Smalltalk-80 programmer always creates a new class as
    a subclass of an existing class. A system class named
    Object describes the similarity of all objects in the
    system, so every class will at least be a subclass of
    Object.

    _Smalltalk-80: The Language_, Adele Goldberg and David Robson, 1989.

    There is little or no historical support for the notion that use of
    objects in the absence of inheritance gives object oriented programming.
    The Standard Template Library was (and remains) largely template-based
    -- but C++ was considered an object-oriented programming language long
    before it supported templates at all.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, Feb 19, 2007
    #20
    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. RA Scheltema
    Replies:
    3
    Views:
    407
    RA Scheltema
    Jan 6, 2004
  2. Marijn
    Replies:
    5
    Views:
    471
    Marijn
    Feb 13, 2004
  3. Replies:
    7
    Views:
    555
    Pete Becker
    Jan 25, 2008
  4. Per
    Replies:
    10
    Views:
    521
    James Kanze
    Dec 8, 2008
  5. Sebastian Mach
    Replies:
    5
    Views:
    315
Loading...

Share This Page