ein paar Fragen zum Konstruieren eines Objekts



  • Hallo,

    Ich hätte mal eine kurze Frage, nur um bestätigt zu sein. Und zwar wollte ich wissen ob folgendes stimmt:

    Erst mal der Code.

    class Klasse
    {
        int wert
    
    public:
        Klasse( int Wert ) : wert( Wert ) {}
    };
    
    int main()
    {
        Klasse objekt = Klasse( 42 );
        Klasse* objekt2 = &Klasse( 44 );
        Klasse objekt3( 43 );
        Klasse objekt4;
        Klasse objekt5( );
    }
    

    Habe ich jetzt 4 Objekte erstellt? Denn bei der ersten Anweisung wird doch ein Objekt erstellt, das kopiere ich, der Kopie gebe ich einen Namen und das zuerst erstellte Objekt - mit Klasse(42) - wird vergessen und ist nicht mehr ansprechbar, oder?

    Von daher würde die zweite Anweisung ja mehr Sinn machen, weil ich mir die Adresse des erstellten Objekts einfach merke und kein zweites Objekt erstelle.

    Die dritte Anweisung habe ich in einem Buch gelesen. Die scheint auch zu funktionieren und ich habe sogar das Objekt mit der Variablen objekt3 zur Verfügung und nicht nur die Adresse. Aber mich wundert, dass das funktioniert. Denn es wird doch gar nicht der Konstruktor 'Klasse( int Wert )' aufgerufen...

    Bei der vierten Anweisung wird doch der Standardkonstruktor aufgerufen falls vorhanden, oder? Was ist denn dann der Unterschied zur fünften Anweisung?

    Danke schon mal im Voraus

    MfG Tobi



    1. und 3) sind (spätestens im Release) identisch. Es sieht im Code zwar so aus, als würde da was kopiert werden, wenn mich icht alles täuscht, wird der Konstruktor aber nur einmal aufgerufen, wenn er keine seiteneffekte hat.

    2. ist nicht gut. Du hast einen Zeiger auf ein temporäres Objekt, welches nach der Zeile wohl gleich wieder zerstöärt wird. Also zeigt der Zeiger ins Nirvana.

    3. ruft den Standardkonstruktor auf (der bei dir nicht existiert, gibt also Kompilierfehler, weil du schon eien anderen Konstruktor definiert hast).

    4. ist eine lokale Funktionsdeklaration mit NAmen objekt5 und Rückgabewert Klasse. Also sicherlich nicht, was du meintest 🙂



  • Denn bei der ersten Anweisung wird doch ein Objekt erstellt, das kopiere ich, der Kopie gebe ich einen Namen und das zuerst erstellte Objekt - mit Klasse(42) - wird vergessen und ist nicht mehr ansprechbar, oder?

    Richtig, allerdings kann der Compiler die Kopie hier wegoptimieren.

    Von daher würde die zweite Anweisung ja mehr Sinn machen, weil ich mir die Adresse des erstellten Objekts einfach merke und kein zweites Objekt erstelle.

    Es gilt aber weiterhin Deine Aussage von oben "das zuerst erstellte Objekt wird vergessen". Sprich, Du speicherst die Adresse von etwas, was nicht mehr existiert.

    Die dritte Anweisung habe ich in einem Buch gelesen. Die scheint auch zu funktionieren und ich habe sogar das Objekt mit der Variablen objekt3 zur Verfügung und nicht nur die Adresse. Aber mich wundert, dass das funktioniert. Denn es wird doch gar nicht der Konstruktor 'Klasse( int Wert )' aufgerufen...

    Welcher sonst?

    Bei der vierten Anweisung wird doch der Standardkonstruktor aufgerufen falls vorhanden, oder?

    Ja.

    Was ist denn dann der Unterschied zur fünften Anweisung?

    objekt5 ist kein Objekt vom Typ Klasse, sondern eine Funktion ohne Parameter und dem Rückgabetyp Klasse. Vergleiche die Zeile mal mit

    int main()
    

  • Mod

    Die Initialiserung von object2 ist nicht nur schlecht, sondern unmöglich. Der Adressoperator kann nur auf lvalue angewandt werden - und folglich nicht auf Ausdrücke, die temporäre Objekte erzeugen (es sei denn, der Operator wurde überladen, was hier aber nicht der Fall ist).



  • Also folgender Code konnte bei mir kompiliert werden und i hat beim Debuggen am Schluss den Wert 44. Ich habe jetzt noch den Standardkonstruktor hinzugefügt und ein Attribut (und das fehlende Semikolon). So lässt sich nun auch die vierte Anweisung kompilieren.

    class Klasse
    {
        int wert;
    
    public:
    	Klasse( void ) {}
        Klasse( int Wert ) : wert( Wert ) {}
    };
    
    int main()
    {
        Klasse objekt = Klasse( 42 );
        Klasse* objekt2 = &Klasse( 44 );
        Klasse objekt3( 43 );
        Klasse objekt4;
        Klasse objekt5();
    }
    

    Aber bei dem fünften Anweisung sagt mir der Compiler tatsächlich, ich hätte eine unbenutzte Funktion dekladiert. Woher will der wissen, dass ich nicht den Standardkonstruktor aufrufen wollte?

    Und wegen der Anweisungen 3 - 5: Der Konstruktor muss also nicht wie eine Methode mit 'Klasse( ... )' aufgerufen werden?

    MfG Tobi



  • anderer Tobi schrieb:

    Also folgender Code konnte bei mir kompiliert werden

    Compilererweiterung? Beim VC++ ist das erlaubt, soweit ich weiß. Versuch mal irgendwo auf Strict ANSI oder so zu schalten.

    Aber bei dem fünften Anweisung sagt mir der Compiler tatsächlich, ich hätte eine unbenutzte Funktion dekladiert. Woher will der wissen, dass ich nicht den Standardkonstruktor aufrufen wollte?

    Was du wolltest, ist relativ uninteressant 😉 Die Syntax ist mehrdeutig, und die Entscheidungsregel lautet: Wenn es aussieht wie eine Funktionsdeklaration, dann ist es auch eine.



  • Aha. Verstehe. Ja ich benutzeden Compiler von VC++.

    Danke für die Hilfe!

    MfG Tobi


Anmelden zum Antworten