Array von elternklasse mit kindern füllen, typecast?



  • Hallo!

    ich habe ein problem mit selbsterstellten klassen.Und zwar habe ich eine Elternklase, die über 2 Kinder verfügt, die die elternklasse um eine je eine methode erweitertn.

    class eltern
    {
    	public:
    		eltern(void);
    		virtual ~eltern(void);
    		virtual void tuwas(int i){;};
    	protected:
    		int a;
    		double b;
    };
    
    class kind1 : public eltern
    {
    	public:
    	       void setkind1attribut(int i);
                   void tuwas(int i);
    	private:
    		int kind1attribut;
    };
    
    class kind2 : public eltern
    {
    	public:
    	       void setkind2attribut(int i);
                   void tuwas(int i);
    	private:
    		int kind2attribut;
    };
    

    wenn ich jetzt ein Array: eltern test[5] erstelle, und das beliebig mit kind1 / kind2 fülle, wie kann ich dann auf die methoden der kinder zugreifen?bzw wie kann ich einen typecast von einem eltern-element aus dem array auf ein kind1 bzw kind2 machen? muss ich dafür in den kindern eine spezielle methode schreiben, die mir einen typecast ermöglicht?

    Vielen dank schonmal für hilfe!

    MfG

    Quaki



  • Hi!

    Was soll das da sein:

    virtual void tuwas(int i){;};
    

    Änder das lieber in:

    virtual void tuwas( int i ) = 0;
    

    Ebenso wie diese Methoden:

    void setkind1attribut(int i);
    void setkind1attribut(int i);
    

    Eine virtuelle Methode + zwei Überladungen.
    Dann musst du nicht entscheiden ob es sich um Kind1 oder Kind2 handelt.

    grüße



  • Wenn Du auf eine vererbte Methode zugreifen willst, die in der spezifizierten Klasse evtl. neu implementiert ist, dann verwende auf jeden Fall virtual, dann wird die entsprechend richtige Methode automatisch aufgerufen.
    Wenn Du auf Methoden zugreifen willst, die in der Eltern-Klasse nicht definiert sind, dann musst Du casten soweit ich weiß.
    Allerdings ist das unschön, da sollte man lieber eine virtuelle Methode definieren, die in allen Spezialisierungen überschrieben wird, falls nötig und die entsprechenden anderen Methoden aufruft, die in der Elternklasse evtl. gar nicht vorhanden sind.



  • Okay, gut das du mich wiederholst!
    Als Kontainer würde sich ja etwas wie vektor o.ä. anbieten.

    grüße



  • David_pb schrieb:

    Okay, gut das du mich wiederholst!

    ups! 😉



  • Du kannst abgeleitete Klassen nicht in nem C-Array unterbringen, da diese sich in der Größe von der Basisklasse unterscheiden (können).

    Entweder du machst nen Array aus Zeigern (eltern*[5]) oder (besser) einen std::vector<eltern*>



  • Danke erstmal für die schnellen Antworten!

    Ich würde ja gerne nen Typecast machen, aber der Compiler lässt micht nicht...

    muss ich in meiner Unterklasse eine bestimmte methode implementieren, um überhaupt einen typecast machen zu können?



  • Hi!

    Warum willst du casten? Eigentlich sollte man NIE casten, nur dann wenns wirklich nich anders Möglich ist.

    class Test
    {
      virtual void setAttribute() = 0;
    }
    
    class Test1 : public Test
    {
      void setAttribute() {}
    }
    
    class Test2 : public Test
    {
      void setAttribute() {}
    }
    
    //..
    std::vector< Test *> v;
    
    v.push_back( new Test1 );
    // ...
    

    So brauchst du keinen cast sondern rufst jeweils immer einfach iterator.setAttribute() auf, fertig.

    grüße



  • Also das Problem ist, dass wir zum einen vector in der Vorlesung nicht behandelt haben, und deshalb auch möglichst nicht benutzen sollen, und 2. das es in den beiden unterklassen funktionen gibt, die in der Bassiklasse nicht vorhanden sind/sein sollen.

    Wie sähe denn eine lösung mit pointern aus?

    Sehe ich das richtig, das ich 2 Kontainer haben muss, da ich ja nur so die attribute speichern kann, die zwar in den unterklassen nicht aber in der basisklasse vorkommen?!

    danke für die hilfe schonmal im vorraus!



  • Hi!

    Wenn du weist was für ein Typ dein Pointer ist, kannst du diesen casten und die entsperchenden Funktionen aufrufen, leider weist du das nicht.
    Du kannst mit dem operator typeid den Typ zwar rausbekommen, zum einen muss dann aber die RTTI verfügbar sein zum anderen hattet ihr das wohl auch nicht in der Vorlesung.

    grüße



  • Also wenn ich z.b. 10 Objekte der 2 Unterklassen hab, dann weiss ich schon ob das 1. vom typ 1 oder 2 ist, da der Anwender die Reihenfolge festlegt. Aber ich werde wohl wirklich nicht drum rum kommen, ein Array für Kinder1 und eins für Kinder2 zu machen, oder? Weil ich ja sonst die Attribute die nur in den Unterklassen vorhanden sind nicht speichern kann...



  • Hi!

    Ne, wenn du weist an welcher stelle was für ein Typ steht kannst du auch casten...

    Kind1 *p = static_cast< Kind1 >( array[ index ] );
    p->tuirgendwas();
    

    In array[ index ] muss natürlich wirklich der Typ "Kind1" vorhanden sein. Und außerdem ist casten sowiso gefährlich, kanns garnicht oft genug sagen. 😉

    grüße



  • Mal nen kleines Beispiel für dich:

    #include <iostream>
    using namespace std;
    
    struct Base
    {
    };
    
    struct Derived1 : Base
    {
      int getVal()
      {
         return 13;
      }
    };
    
    struct Derived2 : Base
    {
      const char* getName()
      {
         return "Hello World";
      }
    };
    
    int main()
    {
      Base* objects[10];
    
      for( int i = 0; i < 10; ++i )
      {
          if( i % 2 == 0 )
              objects[ i ] = new Derived1;
          else
              objects[ i ] = new Derived2;
      }
    
      for( int i = 0; i < 10; ++i )
      {
          //rausfinden ob das Objekt ein Derived1 ist
          if( Derived1* p = dynamic_cast< Derived1* >( objects[ i ] ) )
              cout << p->getVal() << endl;
          else//wenn nicht ist es ein Derived2
          {
              Derived2* p = static_cast< Derived2* >( objects[ i ] );
              cout << p->getName() << endl;
          }
      }
    
      for( int i = 0; i < 10; ++i )
         delete objects[ i ];
    }
    

    Allerdings glaube ich, dass dir noch nen paar allgemeine Grundlagen in Sachen Vererbung fehlen, oder ihr noch nicht genug gemacht habt damit du richtig damit umgehen kannst.



  • Man sollte keine läglicheren Sachen dahinschreiben, hier mal ohne den Flüchtigkeitsfehlern (also nen funktionierendes Beispiel):

    #include <iostream>
    using namespace std;
    
    struct Base
    {
    	virtual ~Base(){}
    };
    
    struct Derived1 : Base
    {
    	int getVal()
    	{
    		return 13;
    	}
    };
    
    struct Derived2 : Base
    {
    	const char* getName()
    	{
    		return "Hello World";
    	}
    };
    
    int main()
    {
    	Base* objects[10];
    
    	for( int i = 0; i < 10; ++i )
    	{
    		if( i % 2 == 0 )
    			objects[ i ] = new Derived1;
    		else
    			objects[ i ] = new Derived2;
    	}
    
    	for( int i = 0; i < 10; ++i )
    	{
    		//rausfinden ob das Objekt ein Derived1 ist
    		if( Derived1* p = dynamic_cast< Derived1* >( objects[ i ] ) )
    			cout << p->getVal() << endl;
    		else//wenn nicht ist es ein Derived2
    		{
    			Derived2* p1 = static_cast< Derived2* >( objects[ i ] );
    			cout << p1->getName() << endl;
    		}
    	}
    
    	for( int i = 0; i < 10; ++i )
    		delete objects[ i ];
    }
    


  • Danke für das Beispiel, soweit hab ich das inzwischen auch verstanden.

    was wäre denn jetzt wenn es in Derived1 ein attribut

    int val
    

    gäbe, und in Derived2 ein attribut

    char[20] name
    

    jeweils mit einer get und einer set methode.

    kann ich das attribut überhaupt mit hilfe in einem Objekt auf das ich mit dem Base* Array zugreife speichern? oder geht das nur wenn ich 2Arrays Derived1[] und Derived2[] mache?

    Mfg

    Quaki



  • Der Satz sollte richtig lauten:

    kann ich das attribut überhaupt in einem Objekt auf das ich mit dem Base* Array zugreife speichern? oder geht das nur wenn ich 2Arrays Derived1[] und Derived2[] mache?



  • Wenn du nen Objekt von ner abgeleiteten Klasse mit nem Zeiger zur Basisklasse speicherst, dann steht dir auch nur die Schnittstelle der Basisklasse zur Verfügung, wenn dir die nicht genügen, musst du einen downcast machen, das heißt in der Vererbungshierachi nach unten (also abgleitete klassen) casten, das wäre bei Base dann Derived1 oder Derived2. Wenn du den Typ sicher kennst reicht nen static_cast, wenn du den Typ nicht (sicher) kennst, dann musst du mit dynamic_cast arbeiten.


Anmelden zum Antworten