Type "assurance" of derived classes

Discussion in 'C++' started by Oliver Graeser, Aug 14, 2008.

  1. Hi All,

    I'm coming from Java to C++ and this is one of the very last problems I
    have so far... In Java, if I have, say, a class SISNode that extends
    NetworkNode, I can have a function that returns a NetworkNode but I can
    assure the compiler that it is in fact a SISNode and therefore call the
    method getStatus() that only a SISNode has. Like

    SISnode s,t;
    NetworkNode n;
    n =t;
    n.getStatus();//won't work
    s= (SISNode) n;
    s.getStatus(); //will work
    ....
    ....

    I'm now looking for some way to do this in C++. I do agent-based network
    simulations, and I want to derive all kinds of agents from a generic
    network node type. This network node is supposed to store his neighbours
    in a std::list<GenericNetworkNode> list. Now in the derived classes I
    can obtain the neighbours, but I cannot call their methods unless they
    were already declared in the GenericNetworkNode declaration.

    Anybody knows how to solve this problem? A hint in the right direction
    (keyword) would be more than enough....

    Thanks

    Oliver
    Oliver Graeser, Aug 14, 2008
    #1
    1. Advertising

  2. Oliver Graeser <> writes:

    > Hi All,
    >
    > I'm coming from Java to C++ and this is one of the very last problems
    > I have so far... In Java, if I have, say, a class SISNode that extends
    > NetworkNode, I can have a function that returns a NetworkNode but I
    > can assure the compiler that it is in fact a SISNode and therefore
    > call the method getStatus() that only a SISNode has. Like
    >
    > SISnode s,t;
    > NetworkNode n;
    > n =t;
    > n.getStatus();//won't work
    > s= (SISNode) n;
    > s.getStatus(); //will work


    No it won't.

    > ...
    > ...
    >
    > I'm now looking for some way to do this in C++. I do agent-based
    > network simulations, and I want to derive all kinds of agents from a
    > generic network node type. This network node is supposed to store his
    > neighbours in a std::list<GenericNetworkNode> list. Now in the derived
    > classes I can obtain the neighbours, but I cannot call their methods
    > unless they were already declared in the GenericNetworkNode
    > declaration.
    >
    > Anybody knows how to solve this problem? A hint in the right direction
    > (keyword) would be more than enough....


    This is not possible, with what you wrote above and the assumed
    declarations. You must realise that when you run n=t; you lose all
    the information specific to a SISNode. There is no way to build it
    back.

    That's why I consider that C++ objects should always be allocated
    dynamically and referend thru a pointer.

    If you had written:

    class SISNode:public NetworkNode {...};

    SISNode* s=new SISNode();
    NetworkNode* n=s;

    then you could write:

    SISNode* nAsSISNode=dynamic_cast<SISNode*>n;
    if(nAsSISNode!=0){ nAsSISNode->getStatus(); }



    --
    __Pascal Bourguignon__
    Pascal J. Bourguignon, Aug 14, 2008
    #2
    1. Advertising

  3. On 2008-08-14 12:44, Pascal J. Bourguignon wrote:
    > Oliver Graeser <> writes:
    >
    >> Hi All,
    >>
    >> I'm coming from Java to C++ and this is one of the very last problems
    >> I have so far... In Java, if I have, say, a class SISNode that extends
    >> NetworkNode, I can have a function that returns a NetworkNode but I
    >> can assure the compiler that it is in fact a SISNode and therefore
    >> call the method getStatus() that only a SISNode has. Like
    >>
    >> SISnode s,t;
    >> NetworkNode n;
    >> n =t;
    >> n.getStatus();//won't work
    >> s= (SISNode) n;
    >> s.getStatus(); //will work

    >
    > No it won't.
    >
    >> ...
    >> ...
    >>
    >> I'm now looking for some way to do this in C++. I do agent-based
    >> network simulations, and I want to derive all kinds of agents from a
    >> generic network node type. This network node is supposed to store his
    >> neighbours in a std::list<GenericNetworkNode> list. Now in the derived
    >> classes I can obtain the neighbours, but I cannot call their methods
    >> unless they were already declared in the GenericNetworkNode
    >> declaration.
    >>
    >> Anybody knows how to solve this problem? A hint in the right direction
    >> (keyword) would be more than enough....

    >
    > This is not possible, with what you wrote above and the assumed
    > declarations. You must realise that when you run n=t; you lose all
    > the information specific to a SISNode. There is no way to build it
    > back.
    >
    > That's why I consider that C++ objects should always be allocated
    > dynamically and referend thru a pointer.
    >
    > If you had written:
    >
    > class SISNode:public NetworkNode {...};
    >
    > SISNode* s=new SISNode();
    > NetworkNode* n=s;
    >
    > then you could write:
    >
    > SISNode* nAsSISNode=dynamic_cast<SISNode*>n;
    > if(nAsSISNode!=0){ nAsSISNode->getStatus(); }


    And, assuming that NetworkNode is derived from GenericNetworkNode you
    can then use std::list<GenericNetworkNode*> to store them. Though it
    might be worth to follow Alf's advice and use some kind of smart pointer
    (which would make it std::list<SmartPointerType<GenericNetworkNode> >).

    --
    Erik Wikström
    Erik Wikström, Aug 14, 2008
    #3
  4. Oliver Graeser

    James Kanze Guest

    On Aug 14, 8:03 pm, Erik Wikström <> wrote:
    > On 2008-08-14 12:44, Pascal J. Bourguignon wrote:
    > > Oliver Graeser <> writes:
    > >> I'm coming from Java to C++ and this is one of the very
    > >> last problems I have so far... In Java, if I have, say, a
    > >> class SISNode that extends NetworkNode, I can have a
    > >> function that returns a NetworkNode but I can assure the
    > >> compiler that it is in fact a SISNode and therefore call
    > >> the method getStatus() that only a SISNode has. Like


    > >> SISnode s,t;
    > >> NetworkNode n;
    > >> n =t;
    > >> n.getStatus();//won't work
    > >> s= (SISNode) n;
    > >> s.getStatus(); //will work


    This is supposed to be Java, I suppose.

    The exact equivalent in C++ would be:

    SISnode* s ;
    SISnode* t ;
    NetworkNode* n ;
    n = t ;
    n->getStatus() ; // won't work
    s = dynamic_cast< SISnode* >( n ) ;
    s->getStatus() ; // will work./

    > > No it won't.


    I think his example is supposed to be Java. Otherwise, it won't
    compile.

    > >> ...
    > >> ...


    > >> I'm now looking for some way to do this in C++. I do
    > >> agent-based network simulations, and I want to derive all
    > >> kinds of agents from a generic network node type. This
    > >> network node is supposed to store his neighbours in a
    > >> std::list<GenericNetworkNode> list. Now in the derived
    > >> classes I can obtain the neighbours, but I cannot call
    > >> their methods unless they were already declared in the
    > >> GenericNetworkNode declaration.


    > >> Anybody knows how to solve this problem? A hint in the
    > >> right direction (keyword) would be more than enough....


    The two important points to remember are that C++ has value
    semantics by default, you have to explicitly use pointers or
    references to get reference semantics, and that the equivalent
    to Java's cast operator in C++ is dynamic_cast.

    > > This is not possible, with what you wrote above and the assumed
    > > declarations. You must realise that when you run n=t; you lose all
    > > the information specific to a SISNode. There is no way to build it
    > > back.


    If they above were C++, he'd not loose any type information.
    But he'd get a new object (with a new type), which is probably
    not what he wants.

    > > That's why I consider that C++ objects should always be
    > > allocated dynamically and referend thru a pointer.


    That's valid for entity objects, but not for value objects.

    > > If you had written:


    > > class SISNode:public NetworkNode {...};


    > > SISNode* s=new SISNode();
    > > NetworkNode* n=s;


    > > then you could write:


    > > SISNode* nAsSISNode=dynamic_cast<SISNode*>n;
    > > if(nAsSISNode!=0){ nAsSISNode->getStatus(); }


    > And, assuming that NetworkNode is derived from
    > GenericNetworkNode you can then use
    > std::list<GenericNetworkNode*> to store them. Though it might
    > be worth to follow Alf's advice and use some kind of smart
    > pointer (which would make it
    > std::list<SmartPointerType<GenericNetworkNode> >).


    If these are entity objects, as it would seem, I don't know of a
    smart pointer that would really be appropriate.

    --
    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, Aug 14, 2008
    #4
  5. James Kanze wrote:
    > On Aug 14, 8:03 pm, Erik Wikström <> wrote:
    >> On 2008-08-14 12:44, Pascal J. Bourguignon wrote:
    >>> Oliver Graeser <> writes:
    >>>> I'm coming from Java to C++ and this is one of the very
    >>>> last problems I have so far... In Java, if I have, say, a
    >>>> class SISNode that extends NetworkNode, I can have a
    >>>> function that returns a NetworkNode but I can assure the
    >>>> compiler that it is in fact a SISNode and therefore call
    >>>> the method getStatus() that only a SISNode has. Like

    >
    >>>> SISnode s,t;
    >>>> NetworkNode n;
    >>>> n =t;
    >>>> n.getStatus();//won't work
    >>>> s= (SISNode) n;
    >>>> s.getStatus(); //will work

    >
    > This is supposed to be Java, I suppose.


    Yes, it was supposed to be Java
    >
    > The exact equivalent in C++ would be:
    >
    > SISnode* s ;
    > SISnode* t ;
    > NetworkNode* n ;
    > n = t ;
    > n->getStatus() ; // won't work
    > s = dynamic_cast< SISnode* >( n ) ;
    > s->getStatus() ; // will work./
    >
    >>> No it won't.


    Thanks a lot for that! I will consider what Alf Steinbach wrote above on
    how to do it with a boost::shared_ptr, but in any case this is exactly
    what I was trying to do. The word "dynamic_cast" is actually the key, it
    is really hard to google something when you don't know its name ;)

    > I think his example is supposed to be Java. Otherwise, it won't
    > compile.
    >
    >>>> ...
    >>>> ...

    >
    >>>> I'm now looking for some way to do this in C++. I do
    >>>> agent-based network simulations, and I want to derive all
    >>>> kinds of agents from a generic network node type. This
    >>>> network node is supposed to store his neighbours in a
    >>>> std::list<GenericNetworkNode> list. Now in the derived
    >>>> classes I can obtain the neighbours, but I cannot call
    >>>> their methods unless they were already declared in the
    >>>> GenericNetworkNode declaration.

    >
    >>>> Anybody knows how to solve this problem? A hint in the
    >>>> right direction (keyword) would be more than enough....

    >
    > The two important points to remember are that C++ has value
    > semantics by default, you have to explicitly use pointers or
    > references to get reference semantics, and that the equivalent
    > to Java's cast operator in C++ is dynamic_cast.
    >
    >>> This is not possible, with what you wrote above and the assumed
    >>> declarations. You must realise that when you run n=t; you lose all
    >>> the information specific to a SISNode. There is no way to build it
    >>> back.

    >
    > If they above were C++, he'd not loose any type information.
    > But he'd get a new object (with a new type), which is probably
    > not what he wants.
    >

    Yup. Actually this was a problem I encountered before when I had an
    object a, created a new object b, said b=a, manipulated b and was
    stunned that a was still the same.... I'm sorry, I think the question
    was probably not really well asked, I tried to keep it concise.
    >>> That's why I consider that C++ objects should always be
    >>> allocated dynamically and referend thru a pointer.

    >
    > That's valid for entity objects, but not for value objects.
    >
    >>> If you had written:

    >
    >>> class SISNode:public NetworkNode {...};

    >
    >>> SISNode* s=new SISNode();
    >>> NetworkNode* n=s;

    >
    >>> then you could write:

    >
    >>> SISNode* nAsSISNode=dynamic_cast<SISNode*>n;
    >>> if(nAsSISNode!=0){ nAsSISNode->getStatus(); }

    >
    >> And, assuming that NetworkNode is derived from
    >> GenericNetworkNode you can then use
    >> std::list<GenericNetworkNode*> to store them. Though it might
    >> be worth to follow Alf's advice and use some kind of smart
    >> pointer (which would make it
    >> std::list<SmartPointerType<GenericNetworkNode> >).

    >
    > If these are entity objects, as it would seem, I don't know of a
    > smart pointer that would really be appropriate.


    Ayah. Smart pointer, entity objects, value objects - enough for today to
    read on. Thanks a lot, everyone!

    > --
    > 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
    Oliver Graeser, Aug 15, 2008
    #5
  6. Oliver Graeser

    Triple-DES Guest

    On 15 Aug, 09:16, Oliver Graeser <> wrote:
    > >>> Oliver Graeser <> writes:
    > >>>> I'm coming from Java to C++ and this is one of the very
    > >>>> last problems I have so far... In Java, if I have, say, a
    > >>>> class SISNode that extends NetworkNode, I can have a
    > >>>> function that returns a NetworkNode but I can assure the
    > >>>> compiler that it is in fact a SISNode and therefore call
    > >>>> the method getStatus() that only a SISNode has. Like

    >
    > >>>> SISnode s,t;
    > >>>> NetworkNode n;
    > >>>> n =t;
    > >>>> n.getStatus();//won't work
    > >>>> s= (SISNode) n;
    > >>>> s.getStatus(); //will work

    >
    > > This is supposed to be Java, I suppose.

    >
    > Yes, it was supposed to be Java
    >
    >
    >
    > > The exact equivalent in C++ would be:

    >
    > >     SISnode* s ;
    > >     SISnode* t ;
    > >     NetworkNode* n ;
    > >     n = t ;
    > >     n->getStatus() ;   // won't work
    > >     s = dynamic_cast< SISnode* >( n ) ;
    > >     s->getStatus() ;   // will work./

    >
    > >>> No it won't.

    >
    > Thanks a lot for that! I will consider what Alf Steinbach wrote above on
    > how to do it with a boost::shared_ptr, but in any case this is exactly
    > what I was trying to do. The word "dynamic_cast" is actually the key, it
    > is really hard to google something when you don't know its name ;)


    I'd just like to mention that if the dynamic type of *s happened to be
    something else (not a SISnode), then this would not work. To ensure
    that the cast succeeded, check the pointer against 0.

    s = dynamic_cast<SISnode*>(n);
    if(!s)
    {
    // the cast failed, handle error...
    }

    or:

    if( !(s = dynamic_cast<SISnode*>(n)))
    {
    // handle error...
    }

    I prefer the former.

    DP
    Triple-DES, Aug 15, 2008
    #6
  7. Triple-DES wrote:
    > On 15 Aug, 09:16, Oliver Graeser <> wrote:
    >>>>> Oliver Graeser <> writes:
    >>>>>> I'm coming from Java to C++ and this is one of the very
    >>>>>> last problems I have so far... In Java, if I have, say, a
    >>>>>> class SISNode that extends NetworkNode, I can have a
    >>>>>> function that returns a NetworkNode but I can assure the
    >>>>>> compiler that it is in fact a SISNode and therefore call
    >>>>>> the method getStatus() that only a SISNode has. Like
    >>>>>> SISnode s,t;
    >>>>>> NetworkNode n;
    >>>>>> n =t;
    >>>>>> n.getStatus();//won't work
    >>>>>> s= (SISNode) n;
    >>>>>> s.getStatus(); //will work
    >>> This is supposed to be Java, I suppose.

    >> Yes, it was supposed to be Java
    >>
    >>
    >>
    >>> The exact equivalent in C++ would be:
    >>> SISnode* s ;
    >>> SISnode* t ;
    >>> NetworkNode* n ;
    >>> n = t ;
    >>> n->getStatus() ; // won't work
    >>> s = dynamic_cast< SISnode* >( n ) ;
    >>> s->getStatus() ; // will work./
    >>>>> No it won't.

    >> Thanks a lot for that! I will consider what Alf Steinbach wrote above on
    >> how to do it with a boost::shared_ptr, but in any case this is exactly
    >> what I was trying to do. The word "dynamic_cast" is actually the key, it
    >> is really hard to google something when you don't know its name ;)

    >
    > I'd just like to mention that if the dynamic type of *s happened to be
    > something else (not a SISnode), then this would not work. To ensure
    > that the cast succeeded, check the pointer against 0.


    Thanks for the hint. I'm actually not worried about having nodes with
    the wrong type since every network only has one kind of node, I'm going
    through this ordeal only because I want to keep all reporting methods in
    the same network class.

    I used you hint though to work out another problem. I originally stored
    all my nodes in an array, such as

    GenericNetworkNode * nodeList;//declaration
    ......

    nodeList = new SISNetworkNode[size];//network constructor
    ......
    SISNetworkNode *snn;
    snn=dynamic_cast <SISNetworkNode*> (&nodeList);//here comes the disaster

    I managed to find out that it is something about the array, i.e. if I
    instead use an array of pointers, create a node for each pointer, and
    then do the dynamic cast for nodeList instead of &nodeList, it
    works. Is there any particular reason why dynamic casts doesn't work
    with arrays?




    >
    > s = dynamic_cast<SISnode*>(n);
    > if(!s)
    > {
    > // the cast failed, handle error...
    > }
    >
    > or:
    >
    > if( !(s = dynamic_cast<SISnode*>(n)))
    > {
    > // handle error...
    > }
    >
    > I prefer the former.
    >
    > DP
    Oliver Graeser, Aug 18, 2008
    #7
  8. Oliver Graeser

    Triple-DES Guest

    On 18 Aug, 04:02, Oliver Graeser <> wrote:
    > I used you hint though to work out another problem. I originally stored
    > all my nodes in an array, such as
    >
    > GenericNetworkNode * nodeList;//declaration
    > .....
    >
    > nodeList = new SISNetworkNode[size];//network constructor
    > .....
    > SISNetworkNode *snn;
    > snn=dynamic_cast <SISNetworkNode*> (&nodeList);//here comes the disaster
    >
    > I managed to find out that it is something about the array, i.e. if I
    > instead use an array of pointers, create a node for each pointer, and
    > then do the dynamic cast for nodeList instead of &nodeList, it
    > works. Is there any particular reason why dynamic casts doesn't work
    > with arrays?


    Yes. When you assign an array of SISNetworkNode to a
    GenericNetworkNode*, the array decays to a pointer to the first
    element. This pointer is then converted to a GenericNetworkNode*. The
    fact that this pointer actually points to an array of SISNetworkNode
    is "lost" to the compiler.

    When you later write nodeList, the compiler will compute the memory
    location as if you had an array of GenericNetworkNode, not
    SISNetworkNode. Since SISNetworkNode is almost surely larger than
    GenericNetworkNode you will end up referencing some random memory
    location within the array.

    As you have already figured out, arrays of pointers solves the
    problem. But it would be even better to use std::vector instead and
    avoid arrays.

    DP
    Triple-DES, Aug 18, 2008
    #8
  9. Oliver Graeser

    HL Guest

    On Aug 18, 10:02 am, Oliver Graeser <> wrote:
    > Triple-DES wrote:
    > > On 15 Aug, 09:16, Oliver Graeser <> wrote:
    > >>>>> Oliver Graeser <> writes:
    > >>>>>> I'm coming from Java to C++ and this is one of the very
    > >>>>>> last problems I have so far... In Java, if I have, say, a
    > >>>>>> class SISNode that extends NetworkNode, I can have a
    > >>>>>> function that returns a NetworkNode but I can assure the
    > >>>>>> compiler that it is in fact a SISNode and therefore call
    > >>>>>> the method getStatus() that only a SISNode has. Like
    > >>>>>> SISnode s,t;
    > >>>>>> NetworkNode n;
    > >>>>>> n =t;
    > >>>>>> n.getStatus();//won't work
    > >>>>>> s= (SISNode) n;
    > >>>>>> s.getStatus(); //will work
    > >>> This is supposed to be Java, I suppose.
    > >> Yes, it was supposed to be Java

    >
    > >>> The exact equivalent in C++ would be:
    > >>>     SISnode* s ;
    > >>>     SISnode* t ;
    > >>>     NetworkNode* n ;
    > >>>     n = t ;
    > >>>     n->getStatus() ;   // won't work
    > >>>     s = dynamic_cast< SISnode* >( n ) ;
    > >>>     s->getStatus() ;   // will work./
    > >>>>> No it won't.
    > >> Thanks a lot for that! I will consider what Alf Steinbach wrote above on
    > >> how to do it with a boost::shared_ptr, but in any case this is exactly
    > >> what I was trying to do. The word "dynamic_cast" is actually the key, it
    > >> is really hard to google something when you don't know its name ;)

    >
    > > I'd just like to mention that if the dynamic type of *s happened to be
    > > something else (not a SISnode), then this would not work. To ensure
    > > that the cast succeeded, check the pointer against 0.

    >
    > Thanks for the hint. I'm actually not worried about having nodes with
    > the wrong type since every network only has one kind of node, I'm going
    > through this ordeal only because I want to keep all reporting methods in
    > the same network class.
    >
    > I used you hint though to work out another problem. I originally stored
    > all my nodes in an array, such as
    >
    > GenericNetworkNode * nodeList;//declaration
    > .....
    >
    > nodeList = new SISNetworkNode[size];//network constructor
    > .....
    > SISNetworkNode *snn;
    > snn=dynamic_cast <SISNetworkNode*> (&nodeList);//here comes the disaster
    >
    > I managed to find out that it is something about the array, i.e. if I
    > instead use an array of pointers, create a node for each pointer, and
    > then do the dynamic cast for nodeList instead of &nodeList, it
    > works. Is there any particular reason why dynamic casts doesn't work
    > with arrays?
    >
    >
    >
    >
    >
    > > s = dynamic_cast<SISnode*>(n);
    > > if(!s)
    > > {
    > >   // the cast failed, handle error...
    > > }

    >
    > > or:

    >
    > > if( !(s = dynamic_cast<SISnode*>(n)))
    > > {
    > >   // handle error...
    > > }

    >
    > > I prefer the former.

    >
    > > DP- Hide quoted text -

    >
    > - Show quoted text -- Hide quoted text -
    >
    > - Show quoted text -


    Oliver, your question is exactly about polymorphism.
    polymorphism in C++ is implemented with Pointers and References. You
    can't expect polymorphic behavior on objects.
    And, since they SisNode and NetworkNode are in the same class
    hierarchy, static_cast is supposed to use instead of dynamic_cast. The
    latter is usually used in multi-inheritence casting a base to its
    sibling. But it's so possible to be fail that Triple-DEC mentioned to
    check the result of casting.
    HL, Aug 18, 2008
    #9
    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.

Share This Page