Objekt im Kontruktor



  • Es wird de default-Konstruktor fuer adresse in Kontakt aufgerufen und dann erst a zugewiesen. Moegliche Loesung: Copy-Konstuktor fuer Adresse definierung und in Initialisierungsliste aufrufen.

    PS: Hey, das ist doch C++, es waere besser fuer dich std::string zu verwenden.



  • Adresse hat keinen Standardkonstruktor. Genau aus diesem Grund solltest du die Initialisierungsliste verwenden:

    Kontakt::Kontakt(const char* nn, const char* vn, const Adresse& a)
    : adresse(a)
    {
        // ...
    }
    


  • 🙄

    DANKE!!!

    Nur zum Verständnis... ich muss nochmal dumm fragen 😞

    Ich habe in der Datei Adresse.ccp einen Konstruktor definiert:

    Adresse::Adresse(const char* s, unsigned int p, const char* o) {
    
        strncpy(strasse, s, sizeof(strasse)-1);
        strasse[sizeof(strasse)] = '\0';
    
        plz = p;
    
        strncpy(ort, o, sizeof(ort)-1);
        strasse[sizeof(ort)] = '\0';
    
    }
    

    Dadurch fehlt der Standardkonstruktor? Nur eine Initalisierungsliste habe ich immer als kürzere Alternative zur einfachen Zuweisung gefunden. Heißt das die Initalisierungsliste ersetzt einen Konstruktor ala

    Adresse::Adresse(const Adresse& a);
    

    😕



  • Sobald du irgendeinen Konstruktor deklarierst, wird der Standardkonstruktor nicht mehr automatisch generiert (was so auch sinnvoll ist).

    Trotzdem solltest du std::string verwenden, besonders, wenn du noch nicht so geübt im Umgang mit Speicherverwaltung, Zeigern und Arrays bist. Die Zeile

    strasse[sizeof(strasse)] = '\0';
    

    führt nämlich zu einem Array-Überlauf und erzeugt undefiniertes Verhalten.



  • immer als kürzere Alternative zur einfachen Zuweisung gefunden.

    Nein, nicht immer. Besonders wenn man mit (const) Referenzen arbeitet, dann koennen diese manchmal nur in Initialisierungslisten zugewiesen werden.



  • muss nocham fragen... sorry

    1.)
    ich deklariere eine array char

    char strasse[30];
    

    d.h. ich reserviere 30x1Byte im stack

    2.)
    ich weisse über strncpy() dem array werte zu

    strncpy(strasse, "Musterstr. 2", sizeof(strasse)-1)
    

    mit dem sizeof stelle ich sicher das wirklich nur so viele zeichen in das array kopiert werden wie das array lang ist, das -1 verwende ich um platz zu lassen für \0 (siehe 3.)

    3.)

    strasse[sizeof(strasse)] = '\0';
    

    ich dachte damit kopiere ich nie mehr zeichen in das array als es lang ist 😕 wie kann es zu einem überlauf kommen?



  • Cube schrieb:

    Ich habe in der Datei Adresse.ccp einen Konstruktor definiert: [...]

    Dadurch fehlt der Standardkonstruktor?

    Ja. Der Standardkonstruktor wird vom Compiler nur dann generiert, wenn du selber keinen anderen Ctor deklarierst.

    Nur eine Initalisierungsliste habe ich immer als kürzere Alternative zur einfachen Zuweisung gefunden. Heißt das die Initalisierungsliste ersetzt einen Konstruktor ala

    Adresse::Adresse(const Adresse& a);
    

    😕

    Nein. Eine Initialisierungsliste ist mehr als eine Zuzweisung, es ist wie der Name schon sagt eine Initialisierung. Alle Member der Klasse, die keine PODs sind, werden auf jeden Fall initialisiert. Das heißt, wenn du sie in der initialisierungsliste angibst, wird der entsprechende Konstruktor aufgerufen. Ansonsten wird der Default-Konstruktor implizit aufgerufen. Deshalb ist die Zuweisung im Ctor selber auch nicht so Performant wie wenn du es gleich in der initialisierung angibst:

    class A1
    {
      B b;
    
      A1(B const& b2)  //keine initialisierungsliste: b wird implizit default-konstruiert
      {  
        b = b2; //Zuweisungsoperator von B
      }
    };
    
    class A2
    {
      B b;
    
      A1(B const& b2) : b(b2) //entsprechender Ctor von B wird aufgerufen
      {  
      }
    };
    

    Im Ctor von A1 werden zwei Aktionen ausgeführt, im Ctor von A2 nur eine.



  • Ein Array mit n Elementen hat die Indizes 0..n-1, sprich Dein strasse[sizeof(strasse)] ist genau ein Element drüber.



  • Cube schrieb:

    ich dachte damit kopiere ich nie mehr zeichen in das array als es lang ist 😕 wie kann es zu einem überlauf kommen?

    char strasse[30];
    

    strasse bietet Platz für 30 Zeichen. Deren Indizes reichen von 0 bis 29.

    sizeof(strasse)
    

    ergibt die Grösse des Objekts. Die beträgt 30 (Byte), weil char gerade 1 Byte gross ist.

    strasse[sizeof(strasse)]
    

    entspricht somit strasse[30] , was jenseits der Array-Grenzen liegt.

    Also: Nimm std::string ! Da kannst du dir auch die hässliche Kopie sparen und kommst nicht in Probleme, wenn du mal mehr als 30 Zeichen benötigst. Dein Konstruktor wird dann supereinfach:

    Adresse::Adresse(const std::string& neue_strasse, /* ... */)
    : strasse(neue_strasse)
    {
       // hier ist die ganze Strasse schon kopiert, ohne dass
       // du dafür noch irgendwas tun musst!
    }
    


  • Cube schrieb:

    also hier mal der ganze code:

    //Kontakt.h
    
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include "Adresse.h"
    
    #ifndef _KONTAKT_H_
    #define _KONTAKT_H_
    
    using namespace std;
    

    Du solltest die Include-Guards so setzen, dass sie alles umschließen. Das "using namespace std;" schreibt man gerne für kleine Beispiele dazu, gehört aber nicht in Header-Dateien rein.

    Cube schrieb:

    [...zu viel char*, zu viel friend...]
    

    Cube schrieb:

    char strasse[30]; 	
    strasse[sizeof(strasse)] = '\0';
    

    sizeof(strasse) = 30 * sizeof(char) = 30
    strasse[30] steht aber für das 31ste Zeichen, was es nicht gibt.

    Gruß,
    SP


  • Mod

    Cube schrieb:

    3.)

    strasse[sizeof(strasse)] = '\0';
    

    ich dachte damit kopiere ich nie mehr zeichen in das array als es lang ist 😕 wie kann es zu einem überlauf kommen?

    Arrays beginnen aber mit dem Nullten Element, das heißt in deinem Fall ist 29 das letzte Element.



  • der klassiker!!!... ich danke! das ist einleuchtend 😉



  • Und, hast du schon auf std::string umgestellt? :p


Anmelden zum Antworten