Some complex structure I can't code correctly

Discussion in 'C++' started by doamud, Jun 27, 2006.

  1. doamud

    doamud Guest

    Hello all, I've been trying to reengineer some C code to C++, but got
    stuck on some complex data structure:

    On the C code, there is an "Model" struct used to store various kind of
    data, the exact kind stored in the "type" member. Each kind has
    different data, that is stored in a "value" array. So, if a Model is
    type "Car", the maximum speed is stored in value[0]. If it's a "House",
    value[0] is used to store number of inhabitants. A huge mess!

    Here comes C++ to the rescue, I created a ModelBase class, with
    ModelCar, ModelHouse and so on as derived clases. All models have many
    common data, so this polimorphism works very nicely.

    However, there is also an "Obj" struct, which represents an instance of
    the data stored in a "Model". In C, it is the same mess as with Model
    ("type" member, "value" array)... and along new data needed for all
    Objs, it has a pointer back to the Model it originated from.

    So I created a ObjBase clases, with ObjCat, ObjHouse deriving from it.

    And here is the problem... each Model needs to "spawn" an Obj, using a
    covariant return type function, such as:
    ObjHouse* ModelHouse::spawn();
    But also, each Obj needs to returns a reference to its Model, also
    using covariant return type:
    ModelHouse* ObjHouse::get_model();


    I have this:

    class Model;
    class Obj {
    virtual Model* get_model() = 0;
    };
    class Model {
    virtual Obj* spawn() = 0;
    };

    class ModelHouse;
    class ObjHouse : public Obj {
    ModelHouse* get_model(); // <- ERROR HERE
    };
    class ModelHouse : public Model {
    ObjHouse* spawn();
    };

    Error says "invald covariant return type". Of course, up to that point,
    it doesn't know that ModelHouse derives from Model, but moving
    ModelHouse before ObjHouse, gives a similar error for
    ModelHouse::spawn.

    Any clues on how to solve this? Some pattern to represent this data? I
    have tried some ideas, but nothing works.

    I'm using gcc 3.4.4, btw.

    Thanks.
     
    doamud, Jun 27, 2006
    #1
    1. Advertisements

  2. * :
    The only you can benefit from the covariance is by statically knowing
    the type of object, say, that you have pointer of static type ObjHouse*.
    But in that case you can call a non-virtual function p->houseModel(),
    so in the case where you can benefit from the covariance, you don't need
    it: all you need in that case is a non-virtual function. For the other
    cases you also need a virtual function, of unchanging signature.

    If you plan on supporting derivation from concrete classes you should
    let the non-virtual function call the virtual one and downcast the result.

    That might sound counter-intuitive and downright "wrong", but instead of
    writing umpteen hundred lines explaining it, I'll let you figure it out.
     
    Alf P. Steinbach, Jun 27, 2006
    #2
    1. Advertisements

  3. doamud

    Jim Langston Guest

    The way I would solve this is simply by returning a Model* in all cases.
    Since ModelHouse derives from Model, you can point to a ModelHouse with a
    Model pointer and use polymorphism.
     
    Jim Langston, Jun 27, 2006
    #3
  4. My advice would be :
    class ModelHouse;
    class ObjHouse : public Obj {
    Model *get_model(); // <- ERROR HERE
    };
    class ModelHouse : public Model {
    Obj* spawn();
    };

    then you can do a typecast after calling spawn and get_model.
    Does that help ?

    Regards
    Thorsten
     
    Thorsten Kiefer, Jun 27, 2006
    #4
  5. doamud

    doamud Guest

    Sometimes I need to spawn a Model of unknown type. No derived class
    info needed:

    for ( Model* M = ... )
    Obj* O = M->spawn();

    But also, sometimes a specific kind of Model is spawned, and its unique
    attributes changed:

    ModelHouse* M = ...;
    ObjHouse* O = M->spawn();
    O->set_city("Athens");

    Here I need spawn to use covariance, or dynamic_cast it (that I know
    will always be successful, so a static_cast can be used). Or, instead
    of "spawn", call a "spawnHouse" (ugly).


    The other way around is also true: sometimes I have a big list of Obj*
    and only the base class needs to be accessed, so get_model don't need
    covariance.

    for ( Obj* O = ... )
    Model* M = O->get_model();

    But other times, from a ObjCar I need its model...

    ObjCar* O = ...;
    ModelCar* M = O->get_model();
    cout << M->get_max_speed();

    Same as before: either use covariance on "get_model", or add a
    "get_modelCar"... and the latter is way too ugly.
     
    doamud, Jun 27, 2006
    #5
  6. * :
    No. Quoting myself, "in the case where you can benefit from the
    covariance, you don't need it". Please read what you're responding to
    before responding. You've got a solution. Now go implement it (come
    back if you actually encounter a problem, not for some imagined need).
     
    Alf P. Steinbach, Jun 27, 2006
    #6
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.