1. #1
    Lt. Junior Grade
    Dabei seit
    Jan 2011
    Ort
    Bruchsal
    Beiträge
    400

    [C++] Konstruktor-Aufruf-Suche im Code

    Hallo,

    ich habe hier eine überladene Operatorfunktion und die scheint irgendwo einen Konstruktor zu verwenden, ich verstehe nur nicht wo oder warum. Kann mir das jemand erklären?

    Meine main führt folgendes aus:

    Code:
    Bruch b1(1,2);
    Bruch b2(2,3);
    Bruch b3 = b1 * b2;
    Die überladene Operatorfunktion:
    Code:
    const Bruch & Bruch::operator *= (const Bruch &b)
    {
    [INDENT]return *this = *this * b;[/INDENT]
    }
    Der Konstruktor:
    Code:
    Bruch::Bruch(int z, int n) : zaehler(z), nenner(n)
    {
    [INDENT]cout << "Konstruktor" << endl;[/INDENT]
    }
    Der Kopier-Konstruktor:
    Code:
    Bruch::Bruch(const Bruch &rhs)
    {
    [INDENT]cout << "Kopier-Konstruktor" << endl;
    zaehler = rhs.zaehler; nenner = rhs.nenner;[/INDENT]
    }
    Meiner erwartete Ausgabe wäre:
    Konstruktor...
    Konstruktor...
    Konstruktor...

    Die Ausgabe ist diese:
    Konstruktor...
    Konstruktor...
    Konstruktor...
    Konstruktor...

    Also ein Konstruktoraufruf mehr als gedacht. Wo liegt mein Denkfehler? Oder wo meine Unwissenheit?
    Geändert von derBobby (13.09.2011 um 21:08 Uhr)

  2. Anzeige
    Logge dich ein, um diese Anzeige nicht zu sehen.
  3. #2
    Fleet Admiral
    Dabei seit
    Mai 2010
    Beiträge
    13.184

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    1. Bruch b1(1,2);
    2. Bruch b2(2,3);
    3. + 4. Bruch b3 = b1 * b2;

    Der dritte ist Bruch b3
    der vierte ist das Ergebnis b1 * b2 und der wird dann b3 zugewiesen.
    Baue ggf. einen Kopierkonstruktor Bruch::Bruch(Bruch b) {...}
    und mache
    Bruch b3 (b1 * b2);
    dann hast Du nur 3 Aufrufe zwei Deines Konstruktors und einen des Kopierkonstruktors.
    Macht eure Augen auf um zu sehen, sonst braucht ihr sie um zu weinen.
    Medienkompetenz heißt auch: Nachrichten nach ihrer Vertrauenswürdigkeit selbst zu bewerten, denn im Internet kann jeder Idiot schreiben und man muß alle Informationen selbst bewerten! In den Massenmedien dürfen nur reiche Idioten schreiben! Wer ein kritischer Mensch ist, der wird auch die Medien kritisch nutzen, bei den anderen ist Hopfen und Malz verloren. Also: Nichts glauben, selbst prüfen und selbst denken!

  4. #3
    Lt. Junior Grade
    Dabei seit
    Mär 2007
    Ort
    D:\LSA\SK
    Beiträge
    267

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Fehlt da nicht noch der Code für die reine Multiplikation in deinem Post?

    EDIT: naja, Problem scheint ja schon gelöst...
    Geändert von sash2k2 (13.09.2011 um 20:29 Uhr)

  5. #4
    Lieutenant
    Dabei seit
    Jun 2010
    Ort
    Erlangen
    Beiträge
    567

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Zeig uns mal den kompletten Code. Also inklusive operator * und Kopierkonstruktor. Dein operator *= ist außerdem etwas seltsam implementiert. Normalerweise nutzt man in der Implementierung von operator * den operator *= und nicht umgekehrt. Also:

    Code:
    class Bruch
    {
    public:
    	Bruch(int z, int n) : zaehler(z), nenner(n)
    	{
    		cout << "Konstruktor" << endl; 
    	}
    	
    	Bruch( const Bruch& rhs ) : zaehler( rhs.zaehler ), nenner( rhs.nenner )
    	{
    		cout << "Kopierkonstruktor" << endl;
    	}
    	
    	Bruch& operator *= ( const Bruch& rhs )
    	{
    		zaehler *= rhs.zaehler;
    		nenner *= rhs.nenner;
    		
    		return *this;
    	}
    	
    	Bruch operator * ( const Bruch& rhs ) const
    	{
    		Bruch result( *this );
    		result *= rhs;
    		return result;
    		
    		// könnte man noch kürzen schreiben:
    		//return Bruch( *this ) *= b;
    	}
    	
    
    private:
    	int zaehler;
    	int nenner;
    
    };
    Ergänzung vom 13.09.2011 20:36 Uhr:
    Zitat Zitat von Holt Beitrag anzeigen
    [...]und mache
    Bruch b3 (b1 * b2);
    dann hast Du nur 3 Aufrufe zwei Deines Konstruktors und einen des Kopierkonstruktors.
    An dieser Stelle möchte ich mal anmerken, daß

    Bruch b3 (b1 * b2);

    lediglich ein andere Schreibweise für

    Bruch b3 = b1 * b2;

    ist. In beiden Fällen wird b3 über den Kopierkonstruktor erstellt.
    Geändert von antred (13.09.2011 um 22:28 Uhr)

  6. #5
    Lt. Junior Grade
    Ersteller dieses Themas

    Dabei seit
    Jan 2011
    Ort
    Bruchsal
    Beiträge
    400

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Zitat Zitat von sash2k2 Beitrag anzeigen
    Fehlt da nicht noch der Code für die reine Multiplikation in deinem Post?
    Was heißt reine Multiplikation? Bruch * Int?

    Zitat Zitat von antred Beitrag anzeigen
    Zeig uns mal den kompletten Code. Also inklusive operator * und Kopierkonstruktor. Dein operator *= ist außerdem etwas seltsam implementiert. Normalerweise nutzt man in der Implementierung von operator * den operator *= und nicht umgekehrt.
    Kopierkonstruktor brauche ich ja atm nicht zum Verstehen, denke ich. operator* habe ich nicht, die Multiplikation funktioniert auch ohne.

    Ich denke mir fehlt einfach das Verständniss für die Zeile:
    this* = *this * b;
    In dieser müsste ja dann der vierte Aufruf stattfinden, oder etwa im Funktionskopf?

    EDIT:
    Zitat Zitat von antred
    An dieser Stelle möchte ich mal anmerken, daß
    Bruch b3 (b1 * b2);
    lediglich ein andere Schreibweise für
    Bruch b3 = b1 * b2;
    ist. In beiden Fällen wird b3 über den Kopierkonstruktor erstellt.
    Oh Mann, natürlich! Kopierkonstruktor. Das liegt in keiner Weise am *this. Tja, das ist das tolle am Quellcode, da passieren Dinge, die da gar nicht explizit stehen Danke euch allen!

    EDIT2:
    Heißt das dann, dass es immer der Kopierkonstruktor ist, wenn da steht:
    Bruch b5 = *whatever* ?
    Geändert von derBobby (13.09.2011 um 20:42 Uhr)

  7. #6
    Lieutenant
    Dabei seit
    Jun 2010
    Ort
    Erlangen
    Beiträge
    567

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Und jetzt noch was. Wenn du mit Optimierungen übersetzt, kann es sogar passieren, daß am Ende weniger Kopierkonstruktoraufrufe rauskommen, als man erwarten würde, denn es ist dem Compiler freigestellt, sogenannte "temporaries" wegzuoptimieren, SELBST WENN DER KOPIERKONSTRUKTOR NEBENEFFEKTE HAT (und somit der Programmablauf durch das Wegoptimieren der Kopierkonstruktoren verändert würde)!

    http://en.wikipedia.org/wiki/Copy_elision

  8. #7
    Lt. Junior Grade
    Ersteller dieses Themas

    Dabei seit
    Jan 2011
    Ort
    Bruchsal
    Beiträge
    400

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Dann kann man sich damit quasi auch noch das Programm zerschiessen? Sind ja super Möglichkeiten!
    EDIT: Bitte frage am Ende meines letzten Posts nicht überlesen!

  9. #8
    Lieutenant
    Dabei seit
    Jun 2010
    Ort
    Erlangen
    Beiträge
    567

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Zitat Zitat von derBobby Beitrag anzeigen
    EDIT2:
    Heißt das dann, dass es immer der Kopierkonstruktor ist, wenn da steht:
    Bruch b5 = *whatever* ?

    Wenn *whatever* ein Bruch ist oder ein Ausdruck, der als Ergebnis eine Bruch-Instanz liefert, dann ja. Wenn auf der rechten Seite ein Ausdruck steht, der keine Bruch-Instanz liefert, dann wird der Compiler versuchen, einen Kandidaten zu finden, mit dem das Ding auf der rechten Seite in einen Bruch-Instanz konvertiert werden kann (nicht als explicit deklarierte Bruch-Konstruktoren mit einem Argument oder einen geeigneten cast-Operator).

    Ergänzung vom 13.09.2011 20:56 Uhr:
    Zitat Zitat von derBobby Beitrag anzeigen
    Dann kann man sich damit quasi auch noch das Programm zerschiessen? Sind ja super Möglichkeiten!
    Nur wenn deine Kopierkonstruktoren noch Nebeneffekte haben (also mehr machen, als nur eine Kopie zu erstellen) und du dich absolut auf diese Nebeneffekte verläßt. Das wäre dann aber ohnehin bad practice.

  10. #9
    Lt. Junior Grade
    Ersteller dieses Themas

    Dabei seit
    Jan 2011
    Ort
    Bruchsal
    Beiträge
    400

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    *this = *this * b;

    Was davon ruft dann aber den Konstruktor auf, bzw. muss umgewandelt werden? Hinter dem *this steht der erste Bruch vor dem Operator *= und b ist ja auch schon ein Bruch. Also dürfte es doch keinen Aufruf geben?

    EDIT: Kopierkonstruktor der Vollständigkeit halber eingebaut. Code siehe oben.
    Geändert von derBobby (13.09.2011 um 21:07 Uhr)

  11. #10
    Lieutenant
    Dabei seit
    Jun 2010
    Ort
    Erlangen
    Beiträge
    567

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Zitat Zitat von derBobby Beitrag anzeigen
    *this = *this * b;

    Was davon ruft dann aber den Konstruktor auf, bzw. muss umgewandelt werden? Hinter dem *this steht der erste Bruch vor dem Operator *= und b ist ja auch schon ein Bruch. Also dürfte es doch keinen Aufruf geben?
    Moment, ich sprach von

    Bruch b3 = b1 * b2;

    ! Folgendes:

    Bruch b3;
    b3 = b1 * b2;


    Wäre schon wieder ein völlig andere Geschichte.

    Hier würde b3 erst mal über einen parameterlosen Defaultkonstruktor erstellt (es sei denn, deine Klasse hat keinen ... dann würde sich die Zeile Bruch b3; überhaupt nicht kompilieren lassen). Anschließend würde dann das Ergebnis von b1 * b2 berechnet. Diese Berechnung gibt eine "temporary" zurück, die mit dem Kopierkonstruktor erstellt wird. Diese temporary wird dann mit dem Zuweisungsoperator (operator =) an b3 zugewiesen.

    Ergänzung vom 13.09.2011 21:13 Uhr:
    Zitat Zitat von derBobby Beitrag anzeigen
    EDIT: Kopierkonstruktor der Vollständigkeit halber eingebaut. Code siehe oben.
    Ich würde dir raten, zaehler und nenner nicht im Rumpf des Kopierkonstruktors sondern, wie du es bei dem anderen Konstruktor auch getan hast, mit einer Initialisierungsliste zu initialisieren.

  12. #11
    Lt. Junior Grade
    Ersteller dieses Themas

    Dabei seit
    Jan 2011
    Ort
    Bruchsal
    Beiträge
    400

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Also schön, neuer Gedanke um meine Frage richtig zu formulieren.

    Code:
    Bruch b1(1,1);
    Bruch b2(1,1);
    
    b1 = b2 * b2; <- diese Zeile ruft einmal Konstruktor und einmal Destruktor auf.
    Die Frage ist jetzt halt, was genau in der Funktion löst den Konstruktor aus, weil *this im Prinzip ein Bruch ist, genauso wie b?:

    Code:
    const Bruch & Bruch::operator *= (const Bruch &b){
    [INDENT]return *this = *this * b;[/INDENT]
    }
    Geändert von derBobby (13.09.2011 um 21:20 Uhr)

  13. #12
    Lieutenant
    Dabei seit
    Jun 2010
    Ort
    Erlangen
    Beiträge
    567

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Zitat Zitat von derBobby
    operator* habe ich nicht, die Multiplikation funktioniert auch ohne.

    Kann nicht sein. Irgend wo in deinem Programm muß ein operator * für 2 Operanden vom Typ Bruch definiert sein, sonst würde sich dein Code nicht kompilieren lassen. Und eben diesen operator * solltest du jetzt mal rausrücken, denn von der Implementierung hängt ab, was bei

    Bruch a( 1, 2 );
    Bruch b( 3, 4 );

    Bruch c = a * b;

    eigentlich so abläuft. Notfalls schmeiß halt mal deinen Debugger an und steppe durch a * b; nur um zu sehen, wo dieser operator eigentlich definiert ist.

  14. #13
    Lt. Junior Grade
    Ersteller dieses Themas

    Dabei seit
    Jan 2011
    Ort
    Bruchsal
    Beiträge
    400

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Ich könnt mich schlagen! Wie blind kann ein Einzelner sein?

    Code:
    inline Bruch Bruch::operator * (const Bruch &b) const
    {
    return Bruch(zaehler * b.zaehler, nenner * b.nenner);
    }
    *AufKnienRumRutschUndUmVerzeihungBitt*
    Und auf einmal ist es sogar mir klar. Bevor ich hier gepostet hab, bin ich den Code zwei Mal durch und habe nach der Operator-Funktion gesucht. Zwei Mal überlesen...

    Kann man die Fkt auch so gestalten, dass kein weiterer Konstruktor notwendig ist?

  15. #14
    Lieutenant
    Dabei seit
    Jun 2010
    Ort
    Erlangen
    Beiträge
    567

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Nee. Ich würde den operator * zwar so schreiben, daß er unter der Haube letztendlich die Implementierung vom operator *= nutzt ... aber ist Geschmackssache. Aber um den Konstruktor für die temporary kommst du nicht umhin. Aber keine Sorge, moderne Compiler sind beim Optimieren ziemlich aggressiv, und so manche temporary wird in einem optimierten Build einfach wegfallen.

  16. #15
    Fleet Admiral
    Dabei seit
    Mai 2010
    Beiträge
    13.184

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Doch, Du kannst einen Konstruktor schreiben, der zwei Brüche aufnimmt und diese multipliziert:

    Bruch( const Bruch& mb1, const Bruch& mb2 )
    {
    zaehler = mb1.zaehler * mb2.zaehler;
    nenner = mb1.nenner * mb2.nenner;
    }

    Wenn Du das aber auch für z.B. die Division machen willst, dann hast Du ein Problem.
    Macht eure Augen auf um zu sehen, sonst braucht ihr sie um zu weinen.
    Medienkompetenz heißt auch: Nachrichten nach ihrer Vertrauenswürdigkeit selbst zu bewerten, denn im Internet kann jeder Idiot schreiben und man muß alle Informationen selbst bewerten! In den Massenmedien dürfen nur reiche Idioten schreiben! Wer ein kritischer Mensch ist, der wird auch die Medien kritisch nutzen, bei den anderen ist Hopfen und Malz verloren. Also: Nichts glauben, selbst prüfen und selbst denken!

  17. #16
    Lieutenant
    Dabei seit
    Jun 2010
    Ort
    Erlangen
    Beiträge
    567

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Das ändert nicht das geringste an der Zahl der Konstruktordurchläufe, die für den operator * stattfinden. Wenn du das anders siehst, erklär's mir bitte.

  18. #17
    Fleet Admiral
    Dabei seit
    Mai 2010
    Beiträge
    13.184

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    antred, wo wird denn bei der Lösung mit dem "Bruch( const Bruch& mb1, const Bruch& mb2 )" Konstruktor noch ein weiterer Konstruktor aufgerufen?
    Macht eure Augen auf um zu sehen, sonst braucht ihr sie um zu weinen.
    Medienkompetenz heißt auch: Nachrichten nach ihrer Vertrauenswürdigkeit selbst zu bewerten, denn im Internet kann jeder Idiot schreiben und man muß alle Informationen selbst bewerten! In den Massenmedien dürfen nur reiche Idioten schreiben! Wer ein kritischer Mensch ist, der wird auch die Medien kritisch nutzen, bei den anderen ist Hopfen und Malz verloren. Also: Nichts glauben, selbst prüfen und selbst denken!

  19. #18
    Lieutenant
    Dabei seit
    Jun 2010
    Ort
    Erlangen
    Beiträge
    567

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Zitat Zitat von Holt Beitrag anzeigen
    antred, wo wird denn bei der Lösung mit dem "Bruch( const Bruch& mb1, const Bruch& mb2 )" Konstruktor noch ein weiterer Konstruktor aufgerufen?
    Um etwaige Mißverständnisse auszuschließen, es geht darum, derBobby's Implementierung für den "operator *", welche zur Zeit so aussieht:

    Code:
    inline Bruch Bruch::operator * (const Bruch &b) const
    {
    	return Bruch(zaehler * b.zaehler, nenner * b.nenner);
    }
    so zu gestalten, daß der Kopier-Konstruktor für die von der Methode zurückgegebenen temporary entfällt. Das ist schlicht und ergreifend nicht möglich. Die von dir vorgeschlagene Implementierung für den "operator *":

    Code:
    Bruch( const Bruch& mb1, const Bruch& mb2 )
    {
    	zaehler = mb1.zaehler * mb2.zaehler;
    	nenner = mb1.nenner * mb2.nenner;
    }
    
    inline Bruch Bruch::operator * (const Bruch &b) const
    {
    	return Bruch( *this, b );
    }
    erzeugt diesen temporary genauso wie jede andere mögliche (korrekte) Implementierung von "operator *".
    Geändert von antred (18.09.2011 um 12:46 Uhr)

  20. #19
    Fleet Admiral
    Dabei seit
    Mai 2010
    Beiträge
    13.184

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Wo wird denn bitte bei dem Konstruktor ein Temporary erzeugt:

    Bruch( const Bruch& mb1, const Bruch& mb2 )
    {
    zaehler = mb1.zaehler * mb2.zaehler;
    nenner = mb1.nenner * mb2.nenner;
    }

    Den * operator nutze ich nicht, denn mit dem kommt man um einen temporary nicht herum, den es aber zu verhindern ging, so wie ich das verstanden habe.

    Aber egal, ich klinge mich jetzt hier aus.
    Macht eure Augen auf um zu sehen, sonst braucht ihr sie um zu weinen.
    Medienkompetenz heißt auch: Nachrichten nach ihrer Vertrauenswürdigkeit selbst zu bewerten, denn im Internet kann jeder Idiot schreiben und man muß alle Informationen selbst bewerten! In den Massenmedien dürfen nur reiche Idioten schreiben! Wer ein kritischer Mensch ist, der wird auch die Medien kritisch nutzen, bei den anderen ist Hopfen und Malz verloren. Also: Nichts glauben, selbst prüfen und selbst denken!

  21. #20
    Lieutenant
    Dabei seit
    Jun 2010
    Ort
    Erlangen
    Beiträge
    567

    [C++] AW: Konstruktor-Aufruf-Suche im Code

    Holt, DerBobby's Frage lautete doch ganz klar:

    Kann man die Fkt auch so gestalten, dass kein weiterer Konstruktor notwendig ist?
    Und da er nur ein paar Zeilen über dieser Frage seine Implementierung vom operator * postete, ist es doch nicht unvernünftig, anzunehmen daß er mit "die Fkt" den operator * meinte, oder?

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •