Objekt im Kontruktor



  • ok erstmal danke für die geduld 😉
    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;
    
    class Kontakt {
    
          private:
    
          //Member-Eigenschaften      
          char name[30];
          char vorname[30];
          Adresse adresse;
    
          public:
    
          //Konstruktoren
          Kontakt(const char* nn, const char* vn, const Adresse& a);
    
          //Getter-Methode
          char get_name();
          char get_vorname();
    
          //Setter-Methode
          void set_name(const char* nn);
          void set_vorname(const char* vn);
    
          //Ausgabe Kontakt
          void print();  
    
    };
    
    #endif
    
    //Kontakt.cpp
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include "Kontakt.h"
    
    //Konstruktoren
    Kontakt::Kontakt(const char* nn, const char* vn, const Adresse& a) { //Zeile 9 Fehler no matching function for call to `Adresse::Adresse()' 
    
                  strncpy(name, nn, sizeof(name)-1);
                  name[sizeof(name)] = '\0';
    
                  strncpy(vorname, vn, sizeof(vorname)-1);
                  vorname[sizeof(vorname)] = '\0';
    
                  adresse = a;
    }
    
    //Ausgabe Kontakt
    void Kontakt::print() {
         cout << "Name:    " << name << endl 
              << "Vorname: " << vorname << endl << endl;
    }
    
    //Getter-Methode
    char Kontakt::get_name() {
         return *name;
    }
    
    char Kontakt::get_vorname() {
         return *vorname;
    }
    
    //Setter-Methode
    void Kontakt::set_name(const char* nn) {
         strncpy(name, nn, sizeof(name)-1);
         name[sizeof(name)] = '\0';
    }
    
    void Kontakt::set_vorname(const char* vn) {
         strncpy(vorname, vn, sizeof(vorname)-1);
         vorname[sizeof(vorname)] = '\0';
    }
    
    //Adresse.h
    
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    
    #ifndef _ADRESSE_H_
    #define _ADRESSE_H_
    
    using namespace std;
    
    class Adresse {
    
          friend class Kontakt;
    
          private:
    
          //Member-Eigenschaften
          char strasse[50];
          unsigned int plz;
          char ort[50];
    
          public:
    
          //Konstruktoren
          Adresse(const char* s, unsigned int p, const char* o);
    
          //Getter-Methode
          char get_strasse();
          int get_plz();
          char get_ort();
    
          //Setter-Methode
          void set_strasse(const char* s);
          void set_plz(int p);
          void set_ort(const char* o);
    
          //Ausgabe Adresse
          void print();
    
    };
    
    #endif
    
    //Adresse.cpp
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include "Adresse.h"
    
    //Konstruktor
    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';
    
    }           
    
    //Ausgabe Adresse
    void Adresse::print() {
         cout << strasse << endl << plz << " " << ort << endl << endl;    
    }           
    
    //Getter-Methode
    char Adresse::get_strasse() {
         return *strasse;
    }
    
    int Adresse::get_plz() {
        return plz;
    }
    
    char Adresse::get_ort() {
         return *ort;
    }
    
    //Setter-Methode
    void Adresse::set_strasse(const char* s){
         strncpy(strasse, s, sizeof(strasse)-1);
         strasse[sizeof(strasse)] = '\0';
    }
    
    void Adresse::set_plz(int p){
         plz = p;
    }
    
    void Adresse::set_ort(const char* o){
         strncpy(ort, o, sizeof(ort)-1);
         strasse[sizeof(ort)] = '\0';
    }
    
    //main.cpp
    
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include "Kontakt.h"
    #include "Adresse.h"
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {   
        Adresse *a1 = new Adresse("Deck 11", 1000, "DS9");
        a1->print();
    
        Kontakt *k1 = new Kontakt("Sisko", "Benjamin", *a1);
        k1->print();
    
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    

    Die komplette Fehlermeldung:
    E:\pAppz\MyDev\Dev-Cpp\Projekte\CPP01_Kontakte\Kontakt.cpp In constructor Kontakt::Kontakt(const char*, const char*, const Adresse&)': 9 E:\\pAppz\\MyDev\\Dev-Cpp\\Projekte\\CPP01_Kontakte\\Kontakt.cpp no matching function for call toAdresse::Adresse()'
    note E:\pAppz\MyDev\Dev-Cpp\Projekte\CPP01_Kontakte\Adresse.h:12 candidates are: Adresse::Adresse(const Adresse&)
    note E:\pAppz\MyDev\Dev-Cpp\Projekte\CPP01_Kontakte\Adresse.h:12 Adresse::Adresse(const char*, unsigned int, const char*)
    E:\pAppz\MyDev\Dev-Cpp\Projekte\CPP01_Kontakte\Makefile.win [Build Error] [Kontakt.o] Error 1

    😕



  • Cube schrieb:

    ok erstmal danke für die geduld 😉
    also hier mal der ganze code:

    ...
    

    Irgendwer hat scheinbar vergessen zu erwähnen dass das Problem auf das wesentliche reduziert werden sollte. Also ein Quellcode, der das Problem beinhaltet, compiliert, aber auch nicht mehr. Beim Reduzieren des Codes kommt man oft selber auf den Kern des Problems - weil der Reduzierte Code eben nicht viel mehr als dieser Kern ist.

    Die komplette Fehlermeldung:
    E:\pAppz\MyDev\Dev-Cpp\Projekte\CPP01_Kontakte\Kontakt.cpp In constructor Kontakt::Kontakt(const char*, const char*, const Adresse&)': 9 **E:\\pAppz\\MyDev\\Dev-Cpp\\Projekte\\CPP01_Kontakte\\Kontakt.cpp no matching function for call toAdresse::Adresse()'**
    note E:\pAppz\MyDev\Dev-Cpp\Projekte\CPP01_Kontakte\Adresse.h:12 candidates are: Adresse::Adresse(const Adresse&)
    note E:\pAppz\MyDev\Dev-Cpp\Projekte\CPP01_Kontakte\Adresse.h:12 Adresse::Adresse(const char*, unsigned int, const char*)
    E:\pAppz\MyDev\Dev-Cpp\Projekte\CPP01_Kontakte\Makefile.win [Build Error] [Kontakt.o] Error 1

    😕

    Da stehts doch schon. Es gibt keinen Standard-Konstruktor für Adresse. Da du aber ein Adresse-Member in Kontakt hast und im Ctor von Kontakt keine init-Liste, versucht der Compiler, das Adresse-Member per Default-Ctor zu initialisieren. Deshalb -> Initialisierungsliste.



  • 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