Question on c++ faq 21.2 Derived** -> Base**

Discussion in 'C++' started by Filimon Roukoutakis, Mar 3, 2007.

  1. Dear all,
    assuming that through a mechanism, for example reflexion, the Derived**
    is known explicitly. Would it be legal (and "moral") to do this
    conversion by a cast (probably reinterpret would work here)? The
    conversion is done for this purpose: I have an
    std::map<std::string, Base*>. I want to "associate" Derived* handles to
    the stored Base* so when Base* in the map changes (ie points another
    address), the Derived* handle outside of the map is updated
    automatically to point to the new address also. Actually what I do for
    the moment is that I make the association using eg
    Map.Associate(std::string name, Derived*&), where Map is a class
    containing the mentioned std::map but I guess this is related to the
    title of the post (Is Derived*& -> Base*& moral?). This is the only
    reason for the conversion, the Derived objects are to be handled only by
    the Derived* pointers. Could there be a better solution that I fail to
    see? I need to use a polymorphic container because I have several
    Derived* types. Thanks,

    filimon
     
    Filimon Roukoutakis, Mar 3, 2007
    #1
    1. Advertising

  2. Filimon Roukoutakis wrote:
    > Dear all,
    > assuming that through a mechanism, for example reflexion, the Derived**
    > is known explicitly. Would it be legal (and "moral") to do this
    > conversion by a cast (probably reinterpret would work here)? The
    > conversion is done for this purpose: I have an
    > std::map<std::string, Base*>. I want to "associate" Derived* handles to
    > the stored Base* so when Base* in the map changes (ie points another
    > address), the Derived* handle outside of the map is updated
    > automatically to point to the new address also. Actually what I do for
    > the moment is that I make the association using eg
    > Map.Associate(std::string name, Derived*&), where Map is a class
    > containing the mentioned std::map but I guess this is related to the
    > title of the post (Is Derived*& -> Base*& moral?). This is the only
    > reason for the conversion, the Derived objects are to be handled only by
    > the Derived* pointers. Could there be a better solution that I fail to
    > see? I need to use a polymorphic container because I have several
    > Derived* types. Thanks,
    >
    > filimon


    Well using reinterpret_cast would work, but the danger is simple. There
    is no guarantee in this design that when you change the Base pointer
    that you don't change it to point to an object of a different type,
    therefore you run the risk of ending up with Derived1* pointing at an
    object of type Derived2.

    Whether this risk is worth running or whether you can't smarten up the
    design somehow so it's intrinsically impossible is not a question I can
    answer for you. But personally I would try and improve the design. Why
    do you need to handle Derived pointers at all? Can't you use Base
    pointers thoughtout. If you really need a Derived pointer then use
    dynamic_cast to obtain it when you need it, rather than storing Derived
    pointers in your data structures.

    john
     
    John Harrison, Mar 3, 2007
    #2
    1. Advertising

  3. John Harrison wrote:
    > Filimon Roukoutakis wrote:
    >> Dear all,
    >> assuming that through a mechanism, for example reflexion, the
    >> Derived** is known explicitly. Would it be legal (and "moral") to do
    >> this conversion by a cast (probably reinterpret would work here)? The
    >> conversion is done for this purpose: I have an
    >> std::map<std::string, Base*>. I want to "associate" Derived* handles
    >> to the stored Base* so when Base* in the map changes (ie points
    >> another address), the Derived* handle outside of the map is updated
    >> automatically to point to the new address also. Actually what I do for
    >> the moment is that I make the association using eg
    >> Map.Associate(std::string name, Derived*&), where Map is a class
    >> containing the mentioned std::map but I guess this is related to the
    >> title of the post (Is Derived*& -> Base*& moral?). This is the only
    >> reason for the conversion, the Derived objects are to be handled only
    >> by the Derived* pointers. Could there be a better solution that I fail
    >> to see? I need to use a polymorphic container because I have several
    >> Derived* types. Thanks,
    >>
    >> filimon

    >
    > Well using reinterpret_cast would work, but the danger is simple. There
    > is no guarantee in this design that when you change the Base pointer
    > that you don't change it to point to an object of a different type,
    > therefore you run the risk of ending up with Derived1* pointing at an
    > object of type Derived2.


    This probably won't be possible. The stored objects are updated by an
    internal procedure that assigns always the same Derived* (by name) on
    the std::map. The type of the Derived* is associated with the name at
    compile time, essentially what is done is that my users have this interface:
    Derived1* t1=Produce<Derived>(name)
    Derived2* t2=Produce<Derived2>(name)
    ....
    Produce stores the objects in std::map<std::string, Base*>, with
    key_val=name
    In this sense, the name (which is used for lookup in std::map) is
    statically bound to the type.

    In another process, after the objects get serialized/deserialized, my
    users use either map lookup or the "handles" we discuss to access the
    objects.

    >
    > Whether this risk is worth running or whether you can't smarten up the
    > design somehow so it's intrinsically impossible is not a question I can
    > answer for you. But personally I would try and improve the design. Why
    > do you need to handle Derived pointers at all? Can't you use Base
    > pointers thoughtout. If you really need a Derived pointer then use
    > dynamic_cast to obtain it when you need it, rather than storing Derived
    > pointers in your data structures.


    The reason for not using Base pointers is that my Derived types have
    different member functions. The only reason that they inherit from Base
    is that I want to keep them in the same std::map (any other
    options/suggestion would be helpful). In addition, I want the user to be
    able to perform operations directly with the Derived* handles without
    having necessarily to lookup the std::map. I assume that the solution
    you suggest for dynamic cast essentially implies
    dynamic_cast<Derived>(std::map::Find(name)->second)->Call
    This could potentially hurt performance (I am talking about several
    thousands of lookups per second).
    Other solution would be to put all possible members as pure virtuals in
    Base, but I would like to avoid this design because it would mean
    essentially either throwing an exception when I do not want to allow an
    operation for eg Derived1 but I want it for Derived2 or putting out a
    message "Do not use this method with Derived1". I do not find these
    solutions very good.
    My question boils down to the following: If I absolutely know the type
    of the Derived* throughout my code, so essentially eliminating the
    reason for using it the wrong way, are there any other dangerous issues
    about this cast (ie could memory alignment problems or something else I
    cannot imagine come into play)?

    filimon
    >
    > john
     
    Filimon Roukoutakis, Mar 3, 2007
    #3
  4. Filimon Roukoutakis wrote:
    > John Harrison wrote:
    >
    >> Filimon Roukoutakis wrote:
    >>
    >>> Dear all,
    >>> assuming that through a mechanism, for example reflexion, the
    >>> Derived** is known explicitly. Would it be legal (and "moral") to do
    >>> this conversion by a cast (probably reinterpret would work here)? The
    >>> conversion is done for this purpose: I have an
    >>> std::map<std::string, Base*>. I want to "associate" Derived* handles
    >>> to the stored Base* so when Base* in the map changes (ie points
    >>> another address), the Derived* handle outside of the map is updated
    >>> automatically to point to the new address also. Actually what I do
    >>> for the moment is that I make the association using eg
    >>> Map.Associate(std::string name, Derived*&), where Map is a class
    >>> containing the mentioned std::map but I guess this is related to the
    >>> title of the post (Is Derived*& -> Base*& moral?). This is the only
    >>> reason for the conversion, the Derived objects are to be handled only
    >>> by the Derived* pointers. Could there be a better solution that I
    >>> fail to see? I need to use a polymorphic container because I have
    >>> several Derived* types. Thanks,
    >>>
    >>> filimon

    >>
    >>
    >> Well using reinterpret_cast would work, but the danger is simple.
    >> There is no guarantee in this design that when you change the Base
    >> pointer that you don't change it to point to an object of a different
    >> type, therefore you run the risk of ending up with Derived1* pointing
    >> at an object of type Derived2.

    >
    >
    > This probably won't be possible. The stored objects are updated by an
    > internal procedure that assigns always the same Derived* (by name) on
    > the std::map. The type of the Derived* is associated with the name at
    > compile time, essentially what is done is that my users have this
    > interface:
    > Derived1* t1=Produce<Derived>(name)
    > Derived2* t2=Produce<Derived2>(name)
    > ...
    > Produce stores the objects in std::map<std::string, Base*>, with
    > key_val=name
    > In this sense, the name (which is used for lookup in std::map) is
    > statically bound to the type.
    >
    > In another process, after the objects get serialized/deserialized, my
    > users use either map lookup or the "handles" we discuss to access the
    > objects.
    >
    >>
    >> Whether this risk is worth running or whether you can't smarten up the
    >> design somehow so it's intrinsically impossible is not a question I
    >> can answer for you. But personally I would try and improve the design.
    >> Why do you need to handle Derived pointers at all? Can't you use Base
    >> pointers thoughtout. If you really need a Derived pointer then use
    >> dynamic_cast to obtain it when you need it, rather than storing
    >> Derived pointers in your data structures.

    >
    >
    > The reason for not using Base pointers is that my Derived types have
    > different member functions. The only reason that they inherit from Base
    > is that I want to keep them in the same std::map (any other
    > options/suggestion would be helpful).


    Make a std::map of void* pointers. If your types are really unrelated
    (as seems to be the case) then that would be more 'honest'.


    In addition, I want the user to be
    > able to perform operations directly with the Derived* handles without
    > having necessarily to lookup the std::map. I assume that the solution
    > you suggest for dynamic cast essentially implies
    > dynamic_cast<Derived>(std::map::Find(name)->second)->Call
    > This could potentially hurt performance (I am talking about several
    > thousands of lookups per second).
    > Other solution would be to put all possible members as pure virtuals in
    > Base, but I would like to avoid this design because it would mean
    > essentially either throwing an exception when I do not want to allow an
    > operation for eg Derived1 but I want it for Derived2 or putting out a
    > message "Do not use this method with Derived1". I do not find these
    > solutions very good.
    > My question boils down to the following: If I absolutely know the type
    > of the Derived* throughout my code, so essentially eliminating the
    > reason for using it the wrong way, are there any other dangerous issues
    > about this cast (ie could memory alignment problems or something else I
    > cannot imagine come into play)?


    No I don't see any problems. Multiple inheritence in one of your derived
    classes could be a problem, but you can avoid even that by using void*
    instead of Base*.

    john
     
    John Harrison, Mar 3, 2007
    #4
    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. qazmlp
    Replies:
    1
    Views:
    577
    qazmlp
    Apr 10, 2005
  2. Replies:
    4
    Views:
    427
    Alf P. Steinbach
    May 23, 2007
  3. Replies:
    1
    Views:
    405
    myork
    May 23, 2007
  4. Replies:
    1
    Views:
    395
    Victor Bazarov
    May 23, 2007
  5. Replies:
    2
    Views:
    721
Loading...

Share This Page