Objekte unterschiedlichen Types mit gleicher Basis im Vector?



  • Hallo,
    ich habe eine Basis mit zwei Sub-Klassen. Ich will Zeiger auf Objekte der Subklassen in einem Vector Speichern. Speichere ich in einem vector<basis*> geht der Type verloren und ich habe nurnoch basis-objekte ( war das das object slicing ???). Habe ich jetzt einen Denkfehler, oder geht das gar nicht? Ich könnte den Type in der basis als string speichern und dann via type_cast wieder hinbiegen aber das kann es ja woh nicht sein. Kann mich mal einer in die richtige Richtung schubsen?? Danke

    Peanut

    #include <iostream>
    #include <string>
    #include <vector>
    
    class basis{};
    class a : public basis{};
    class b : public basis{};
    
    std::string polyfunc( basis* type ){return "basis"; }
    std::string polyfunc( a* type ){return "a"; }
    std::string polyfunc( b* type ){return "b"; }
    
    int main () {
      std::vector<basis*> vec;
      vec.push_back( new a );
      vec.push_back( new b );
      for ( std::vector<basis*>::iterator i=vec.begin();i<vec.end();i++){
        std::cout << polyfunc( *i ) << std::endl;
      }
    }
    

    gibt
    #basis
    #basis
    sollgeben
    #a
    #b



  • kein slicing, kein problem und so.
    musst nur das dispatching vom viruell-trick machen lassen.

    std::string polyfunc( basis* x ){return x->virtpoly() }

    und in basisklasse
    virtual string virtpoly()
    {
    return "basis";
    }
    und in a
    string virtpoly()//virtual in basis
    {
    return "a";
    }



  • Ja, neee. Das soll ja nicht! Dann hätte ich den Objekt-Handler bei den Objekten. Das geht nicht!
    Der Vector soll real so etwas wie Widget-Beschreibungen enthalten und die polyfunc ist eigentlich eine Klasse die die Mediumabhängige aufbereitung besorgt. Content und Engine sollten, wenn irgendwie möglich, getrennt bleiben!



  • Original erstellt von Peanut:
    Ja, neee. Das soll ja nicht! Dann hätte ich den Objekt-Handler bei den Objekten. Das geht nicht!
    Der Vector soll real so etwas wie Widget-Beschreibungen enthalten und die polyfunc ist eigentlich eine Klasse die die Mediumabhängige aufbereitung besorgt. Content und Engine sollten, wenn irgendwie möglich, getrennt bleiben!

    ok, dann besorg ich dirs richtig.

    class BasisBenutzer
    {
      virturl void tuwas(basis* x)=0;
      virturl void tuwas(a* x)=0;
      virturl void tuwas(b* x)=0;
    };
    
    class PolyFunc:public BasisBenutzer
    {
      void tuwas(basis* x){cout<<"basis";};
      void tuwas(a* x){cout<<"a";};
      void tuwas(b* x){cout<<"b"};
    };
    
    class basis
    {
       virtual void tuwas(BasisBenutzer* bb){bb->tuwas(this);}
    };
    class a:public basis
    {
       virtual void tuwas(BasisBenutzer* bb){bb->tuwas(this);}
    };
    class b:public basis
    {
       virtual void tuwas(BasisBenutzer* bb){bb->tuwas(this);}
    };
    


  • Original erstellt von Peanut:
    ... code ....
    gibt
    #basis
    #basis
    sollgeben
    #a
    #b

    Du rufst aber immer

    std::string polyfunc( basis* type ){return "basis"; }
    

    auf, da Du im Vector Objekte vom Typ basis* hast (auch wenn die Instanzen von Basis abgeleitet sind)! Du könntest polyfunc als virtuelle Memberfunction in basis aufnehmen und bei a und b entsprechend überschreiben.

    Naja, Du musst Dich in jedem Fall bei Deinem Container (z.B. vector) festlegen, welchen Typ von Objekten er aufnehmen kann. Deshalb würde ich den Vorschlag nicht als so falsch bezeichnen, in der Basisklasse den Typ zu speichern, um dann entsprechend zu casten. Ich würde allerdings keinen String verwenden, sondern einen Enum, dessen Wert die Basisklasse im Konstruktor übergeben bekommt. Ansonsten fällt mir noch eine andere Lösung ein. Sie ist im Prinzip wieder genau das Gleiche (z.B. "spart" mir das union nur das casten). Andererseits hat Sie den Vorteil, dass man in der Basisklasse den Typ nicht mit aufnehmen muss. Dadurch kann man den Container für beliebige Typen (mussen nicht von einer Basisklasse stammen) gleichzeitig verwenden:

    #include <iostream>
    #include <string>
    #include <vector>
    
    class basis{};
    class a : public basis{};
    class b : public basis{};
    
    enum element_type { etNone, etBasis, etA, etB };
    struct element {
      element_type value_type;
      union {
        basis *basis_ptr;
        a *a_ptr;
        b *b_ptr;
      } value;
    
      element()
      : value_type(etNone)
      { }
    
      element(const element &a_element)
      : value_type(a_element.value_type)
      {
        switch(value_type) {
          case etBasis:
            value.basis_ptr = a_element.value.basis_ptr;
            break;
          case etA:
            value.a_ptr = a_element.value.a_ptr;
            break;
          case etB:
            value.b_ptr = a_element.value.b_ptr;
            break;
          default:
            break;
        }
      }
    
      element(basis &a_value)
      : value_type(etBasis)
      {
        value.basis_ptr = &a_value;
      }
    
      element(a &a_value)
      : value_type(etA)
      {
        value.a_ptr = &a_value;
      }
    
      element(b &a_value)
      : value_type(etB)
      {
        value.b_ptr = &a_value;
      }
    };
    
    int main (int argc, char *argv[]) {
      std::vector<element> vec;
      vec.push_back( element(*(new a)) );
      vec.push_back( element(*(new b)) );
      for ( std::vector<element>::iterator i=vec.begin();i<vec.end();i++){
        switch(i->value_type) {
          case etBasis:
            std::cout << "basis" << std::endl;
            break;
          case etA:
            std::cout << "a" << std::endl;
            break;
          case etB:
            std::cout << "b" << std::endl;
            break;
          default:
            std::cout << "<unknown>" << std::endl;
            break;
        }
      }
      return EXIT_SUCCESS;
    }
    

    Ich hoffe, dass ich Dich damit in die richtige Richtung schubsen konnte!

    Gruß,
    Wischmop



  • ups, gar nicht gesehen, dass hier schon Antworten waren 😕 😕 😕



  • ok, dann besorg ich dirs richtig.

    Tu' es Baby, denn ich weiß tu tust es gut... 😉

    Danke, vielen Dank!
    Ein Aufruf renderWith( Widgetmaker* engine){ engine->render( this ); } ... da muss man erstmal drauf kommen, naja, wer kann der kann... noch ein paar Jahre praxis dann kann ich auch 😉

    edit: Quoting repariert.

    [ Dieser Beitrag wurde am 15.06.2003 um 13:55 Uhr von Peanut editiert. ]



  • visitor nennt sich das.
    wischmop: unsinn.



  • Immer das passende Entwurfsmuster zur hand...

    Gibt es da bessere Doku als den Gamma? Der ist mir meist zu abtrakt! Ich schnall erst das ein Muster auf mein Problem passt wenn mir das einer sagt (so wie hier, halt..).



  • Gibt es da bessere Doku als den Gamma? Der ist mir meist zu abtrakt!

    In diesem Fall kann ich dir "Modern C++ Design - Generic Programming and Design Patterns Applied" von Alexandrescu sowie "Pattern Hatching: Design Patterns Applied" von John Vlissides empfehlen.

    Beide sind deutlich angewandter als das GoF-Buch. Das GoF-Buch ist imo aber eine Voraussetzung für beide Bücher.


Anmelden zum Antworten