Wie kann ich hier die polymorphe toString() aufrufen?



  • Hallo zusammen,

    ich versuche den C++ Polymorphismus zu lernen. Dazu gebe ich Zeichenketten mit toString() aus und will das folgende Beispiel benutzen:

    Aktuell gibt der Code die Ausgabe:

    PC P_abc_def I_P_abc I_P_def
    PC P_hij_abc_def I_P_hij I_P_abc_def
    

    Die gewünschte Ausgabe wäre aber:

    PC P_abc_def I_P_abc I_P_def
    PC P_hij_abc_def I_P_hij I_P_abc_def  I_P_abc I_P_def
    

    D.h. erst toString() auf die Basisklasse und wenn vorhanden nochmal toString() auf die abgeleitete Klasse.
    Wie würde sowas gehen? Ich habe es mit virtual versucht aber das macht noch keinen Unterschied.

    Aktuell habe ich diesen Code:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    
    class P {
      private:
        string nom;
        
      public:
        P(string n) : nom(n) {
        
        }
        
        virtual string toString() const {
    		return "P_" + nom;
    	}
    };
    
    
    
    class I {
      public:
        I(P p_, int a) : p(p_), amount(a) {
    	}
    	
    	string desc() const {
    	   string s;
    	   s += " I_";
    	   // call P::toString or PC::toString() ?
    	   s += p.toString();
    	   
    	   return s;
    	}
      
      private:
        P p;   // could be PC or P
        int amount;
      
    };
    
    
    class R {
    	
    	private:
    	  vector<I> ps;
    	  string nom;
    	  
    	public:
    	   R(string n) : nom(n) {
    	   }
    	   
    	   void add(const P & p) {
    		   I i(p, 100);
    		   ps.push_back(i);
    	   }
    	   
    	   string toString() const {
    		   string s;
    		   for (auto i : ps) {
    			   s += i.desc();
    		   }
    		   return s;
    	   }
    	   
    
    };
    
    
    class PC : public P {
    	
    	private:
    	  R r;
    	
    	
    	public:
    	
    	PC(string n) : P(n), r(n) {
    	}
    	
    	string toString() const {
    		string s;
    		s += "PC ";
    		s += P::toString();
    		s += r.toString();
    		
    		return s;
    	}
    	
    	void addToR(const P & p) {
    		r.add(p);
    	}
    
    
    };
    
    int main() {
    
      P p1("abc");
      P p2("def");
      
      PC pc("abc_def");
      pc.addToR(p1);
      pc.addToR(p2);
      
      cout << pc.toString() << endl;
      
      P p3("hij");
      PC pc2("hij_abc_def");
      pc2.addToR(p3);
      pc2.addToR(pc);
      
      cout << pc2.toString() << endl;
      
      return 0;
      
    }
    
    

    Vielen Dank!



  • Auch wenn dein Code durch die einbuchstabigen Klassennamen nicht gut zu durchschauen ist, aber dein Fehler liegt in der Klasse I: dort übergibst du im Konstruktor immer nur eine Kopie der Basisklasse P, d.h. korrekt muß es so sein:

    class I {
      public:
        I(const P &p_, int a) : p(p_), amount(a) { // <- konstante Referenz
    	}
    	
    	string desc() const {
    	   string s;
    	   s += " I_";
    	   // call P::toString or PC::toString() ?
    	   s += p.toString();
    	   
    	   return s;
    	}
      
      private:
        const P &p; // could be PC or P  // <- konstante Referenz
        int amount;
    };
    

    Dann erhältst du auch die erwartete Ausgabe, s.a. Ideone-Code:

    PC P_abc_def I_P_abc I_P_def
    PC P_hij_abc_def I_P_hij I_PC P_abc_def I_P_abc I_P_def
    

    PS: Dein (falscher) Kommentar "// could be PC or P" hat mich auch schnell auf den Fehler gebracht. 😉



  • vielen dank! diese woche habe ich schon ein paar mal draufgeschaut, gestern abend eine stunde und konnte nicht entdecken was ich vergessen habe... das mit den referenzen ist nicht so einfach aber macht es spannend. zum glück hält das behalten vom gelernten besser wenn es ein bisschen weh getan hat, wie in dieser situation 🙂



  • Hallo,

    falls auch noch jemand auf etwas Puzzle spielen hat, es gäbe noch eine weitere Frage.
    Wenn im I Objekt eine Anzahl (int i) mit aufgenommen wird, sollte die Anzahl der PC sich anpassen.
    Also die "falsche" Ausgabe ist:

    PC P_abc_def
       1 *  I_P_abc
       1 *  I_P_def
    
    PC P_hij_abc_def
       1 *  I_P_hij
       2 *  I_PC P_abc_def
       1 *  I_P_abc
       1 *  I_P_def
    

    Die gesuchte Ausgabe ist:

    PC P_abc_def
       1 *  I_P_abc
       1 *  I_P_def
    
    PC P_hij_abc_def
       1 *  I_P_hij
       2 *  I_PC P_abc_def
       2 *  I_P_abc    <- angepasst
       2 *  I_P_def     <- angepasst
    

    Mein aktueller Stand ist: https://ideone.com/28kOVw



  • Die untere Ausgabe entspricht doch der ersten Ausgabe von PC:

    PC P_abc_def
       1 *  I_P_abc
       1 *  I_P_def
    

    Wie sollte da dann eine 2 erscheinen?
    Die 2 (amount) wird doch bei

    2 *  I_PC P_abc_def
    

    eine Zeile vorher ausgegeben.



  • @Th69 um die anzeige richtig darzustellen, muss irgendwo eine "anpassung" gemacht werden. damit das beispiel mal ein bischen lustiger wird, habe ich es in einen moebel-calculator umgeschrieben. der code ist nun hier: https://ideone.com/RwojiW

    für ein "grosses Regal" braucht es 2schrauben und 8bretter... vielleicht finde ich die passende stelle. danke für die diskussion auf jeden fall!

    `Moebel P_Regal
       1 *  I_P_schrauben
    
       4 *  I_P_brett
    
    
    Moebel P_Grosses_regal
       2 *  I_P_holztuer
    
       2 *  I_Moebel P_Regal
       1 *  I_P_schrauben
    
       4 *  I_P_brett
    ``


  • ein erster versuche mit "anpassen" der teile: https://ideone.com/NCTSx2



  • Willst du das Produkt der Einzelteile darstellen (also in deinem Fall 2*1 bzw. 2*4)?
    Dann mußt du den Faktor an das Unterklassenobjekt weitergeben:

    string desc(int factor) const {
    	string s;
    
    	s += " " + to_string( factor * amount ) + " * ";
    	s += " I_";
    	// call P::toString or Moebel::toString() ?
    	s += p.toString();
    
    	return s;
    }
    
    string toString() const {
    	string s;
    	s += to_string( anzahl_)  + "\n";
    	for (auto i : teile) {
    		s += "  ";
    		s += i.desc( anzahl_ ) + "\n";
    	}
    	return s;
    }
    

    Hier noch als dein geänderter Ideone-Code.


Anmelden zum Antworten