Konstruktorkette läuft nicht wie gedacht



  • Abend liebe liebe Leute,

    in einem anderen Programm würde ich ganz gerne eine Konstruktorkette verwenden, um ein neues Objekt zu erstellen. Leider läuft es nicht wie gedacht. Hab nun etwas rumprobiert und erhalte in meinem Beispielprogramm die gleiche Fehlermeldung (siehe unten). Lösen kann ich es aber auch da nicht 😕

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class hallo1 
    {
    public:
    	hallo1(); 
    	hallo1(string);
    	string getHallo1(); 
    
    	~hallo1();
    
    private:
    	string namehallo1; 
    };
    
    string hallo1::getHallo1()
    {
    	return this->namehallo1; 
    }
    hallo1::hallo1()
    {
    
    }
    hallo1::hallo1(string name)
    {
    	this->namehallo1 = name; 
    }
    
    hallo1::~hallo1()
    {
    }
    
    class hallo2 : public hallo1
    {
    public:
    	hallo2(string);
    	string getHallo2();
    	~hallo2();
    
    private:
    	string namehallo2;
    };
    
    string hallo2::getHallo2()
    {
    	return this->namehallo2; 
    }
    
    hallo2::hallo2(string name) : hallo1(name) 
    {
    	this->namehallo2 = name;
    }
    
    hallo2::~hallo2()
    {
    }
    int main()
    {
    	string h1 = "Hallostring1", h2 = "Hallostring2"; 
    	hallo2 *hip = new hallo2(h1, h2);
    	cout << hip->getHallo1() << endl; 
    	system("pause");
    	return 0; 
    }
    

    Fehlermeldung:
    C2661 - "hallo2::hallo2": Keine überladene Funktion akzeptiert 2 Argumente testingdingend - 63
    E0289 - Keine Instanz des Konstruktors ""hallo2::hallo2"" stimmt mit der Argumentliste überein. testingdingend - 63

    Wenn ich den Konstruktor nicht "in Kette" verwende sondern nur einen Parameter (so wie hallo2 deklariert ist) funktioniert es

    hallo2 *hip = new hallo2(h1);
    

    Aber ich will ja beide 🙂



  • Es gibt keinen Konstruktor, der zwei strings annimmt. Deshalb die Fehlermeldung.

    Ich glaube, du möchtest sowas:

    hallo2::hallo2(const std::string& halloString1, const std::string& halloString2)
    : hallo1(halloString1),
      namehallo2(halloString2)
    {}
    


  • Hab jetzt zu wenig Zeit, muss arbeiten gehen. Ich probier da später nochmal rum. Aber erstmal vielen Dank für deine Antwort.



  • Konstruktorkette - was soll das sein?



  • AnanasPilot schrieb:

    Abend liebe liebe Leute,

    in einem anderen Programm würde ich ganz gerne eine Konstruktorkette verwenden, um ein neues Objekt zu erstellen. Leider läuft es nicht wie gedacht. Hab nun etwas rumprobiert und erhalte in meinem Beispielprogramm die gleiche Fehlermeldung (siehe unten). Lösen kann ich es aber auch da nicht 😕

    ...
    

    Fehlermeldung:
    C2661 - "hallo2::hallo2": Keine überladene Funktion akzeptiert 2 Argumente testingdingend - 63
    E0289 - Keine Instanz des Konstruktors ""hallo2::hallo2"" stimmt mit der Argumentliste überein. testingdingend - 63

    Wenn ich den Konstruktor nicht "in Kette" verwende sondern nur einen Parameter (so wie hallo2 deklariert ist) funktioniert es

    hallo2 *hip = new hallo2(h1);
    

    Aber ich will ja beide 🙂

    Ich glaube du hast noch viele andere Probleme. Eins davon ist das Mischen von C mit C++ 🙂 Weil dein Lehrer oder dein Buch dir anscheinend Müll beibringt.

    Auch wenn das hier nur ein Beispiel ist, solltest du dir gleich von Anfang an einiges abgewöhnen. Ich bin zwar selbst ein Leihe, daher könnte man mich gern korrigieren, aber folgende Punkte springen mir sofort ins Auge:

    - mit Zeile 4 Öffnest du den ganzen std namensraum. Das ist eine sehr schlechte Angewohnheit.

    - Eine Klasse beginnt immer mit private, eine struct mit public. Wenn du es nicht explizit anders brauchst dann mache doch folgendes:

    class hallo1
    {
      std::string namehallo1;
    
      public:
        hallo1();
        hallo1( std::string );
        std::string getHallo1();
    };
    

    Damit sparst du dir viele unnötige Informationen.

    - Wenn du nicht zwangsläufig einen Destruktor brauchst, dann lasse ihn einfach aus. Es ist ebenfalls eine unnötige Information.

    - Du brauchst das this-> nicht in Klassen. Wenn du es auslässt, nimmt es automatisch an du meinst den this pointer.

    - Hör auf das Wort Schlüsselwort new ohne Smart-Pointer zu verwenden. Dann brauchst du auch nichts selbst zu deleten. Die Speicherverwaltung geschieht dann automatisch über den Lebenszyklus deiner Variable. Dein Code verursacht deswegen ein Memory-Leak. Besser wäre folgendes

    #include <memory>
    #include <cstdlib>
    
    int main( int argc , char ** argv )
    {
      std::string h1( "1" );
      std::string h2( "2" );
    
      std::unique_ptr< hallo2 > hip( h1 , h2 );
      std::cout << hip->getHallo1() << std::endl;
    
      system( "pause" );
    
      return EXIT_SUCCESS;
    }
    

    - Quetsche den Code nicht so zusammen. Wir sind nicht im letzten Jahrtausend, dass wir Spalten sparen müssen. Halte in leserlich.

    - Return 0 ist auch keine gute Wahl. Nutze besser RETURN_SUCCES in Kombination mit #include <cstdlib>

    So jetzt dürft ihr mich für meine Fehler in den Korrekturvorschlägen bashen 😉



  • asdsaddsasds schrieb:

    - Eine Klasse beginnt immer mit private, eine struct mit public.

    Was soll denn der Quatsch? Bitte immer erst "public", dann "private". Egal, ob class oder struct. Diejenigen, die diese Klasse später mal benutzen, werden es dir danken. Dann sehen sie nämlich sofort den relevanten (public) Teil, der uninteressante Krams (private) gehört nach unten.



  • manni66 schrieb:

    Konstruktorkette - was soll das sein?

    hallo2::hallo2(string name) : hallo1(name)
    

    Das hier. Oder auch deligierender Konstruktor (so habe ich das mal im Englischen gefunden)

    asdsaddsasds schrieb:

    ...

    Wo mische ich denn C mit C++ ?



  • daddy_felix schrieb:

    Es gibt keinen Konstruktor, der zwei strings annimmt. Deshalb die Fehlermeldung.

    Ich glaube, du möchtest sowas:

    hallo2::hallo2(const std::string& halloString1, const std::string& halloString2)
    : hallo1(halloString1),
      namehallo2(halloString2)
    {}
    

    Es funktioniert jetzt. Vielen Dank 😃



  • AnanasPilot schrieb:

    Oder auch deligierender Konstruktor (so habe ich das mal im Englischen gefunden)

    Ein delegating constructor ist so etwas:

    class Foo {
    public: 
      Foo(char x, int y) {}
      Foo(int y) : Foo('a', y) {} // Foo(int) delegates to Foo(char,int)
    };
    

    http://en.cppreference.com/w/cpp/language/initializer_list



  • AnanasPilot schrieb:

    Wo mische ich denn C mit C++ ?

    Hier

    hallo2 *hip = new hallo2(h1, h2);
    


  • manni66 schrieb:

    ...

    Achso, doch nochmal was anderes 😕
    Die Konstruktorkette wurde mir so von meinem Dozenten vorgestellt, wie ich sie in meinem Beispielprogramm geschrieben habe. Muss das morgen auch sehr wahrscheinlich in einem Testat verwenden.
    Wir bekommen dann aber auch vorgefertigte Klassen und müssen dann Methoden erweitern/schreiben.

    asdsaddsasds schrieb:

    ...

    Und deine Lösung mit unique_ptr ist dann reines c++?

    Mein Dozent ist sehr bemüht darin die Dinge überschaubar zu halten. Ich kann noch nicht einordnen was Sinn ergibt und was nicht.
    Vielleicht wird alles auch erst spezieller wenn es in die Wahlmodule geht. Keine Ahnung 😕



  • AnanasPilot schrieb:

    Und deine Lösung mit unique_ptr ist dann reines c++?

    Ich bin jetzt nicht so bewandert in C oder C++, daher sollte man mich ruhig korrigieren.

    Als erstes solltest du alle Objekte, die du mit new anlegst auch mit delete löschen. Sonst entsteht ein memory leak. Dein Code sollte dann eher so aussehen.

    // erst einmal mit nullptr initialisieren.
    hallo2 *hip = nullptr;
    
    try
    {
      // versuche es zu erzeugen.
      hip = new hallo2(h1, h2);
    catch( std::exception const & e )
    {
      // Fehlerbehandlung falls das Objekt nicht erzeugt werden konnte
    }
    
    // Prüfen ob dein Objekt richtig angelegt werden konnte.
    if( nullptr == hip )
    {
      // Falls nicht, hier kommt Fehlerbehandlung 
    }
    
    // Hier kommt der Arbeitscode
    
    // Wenn du fertig bist
    
    // Prüfen ob nicht eine andere Instanz aufgeräumt hat.
    if( hip != nullptr )
    {
      // falls nicht, dann räumst du auf.
      delete hip;
      hip = nullptr
    }
    

    Für doofe wie mich ist das ganze zu kompliziert. Deswegen verwende ich entweder shared_ptr wenn viele dieses Objekt nutzen oder unique_ptr, wenn ich sicher bin, dass nur ich das Objekt nutze. Es wird dann automatisch aufgeräumt 👍

    Dann wären da noch Nebenbaustellen



  • Kurze Ergänzung zu asdsaddsasds Aussage:
    Du musst den Pointer nach dem delete nicht ein nullptr zuweisen. (Eventuell wenn du den gleichen Pointer nochmal verwenden willst, aber das ist eher untypisch).

    Aber in c++ solltest du dir angewöhnen sogenannte smart pointer zu Verwenden, wenn du dynamisch angelegten Speicher benötigst (std::unique_ptr oder std::shared_ptr).

    In deinem Fall, AnanasPilot, ist die Frage warum überhaupt dynamisch. Warum nicht einfach:

    hallo2 hip(h1, h2);
    


  • asdsaddsasds schrieb:

    AnanasPilot schrieb:

    Wo mische ich denn C mit C++ ?

    Hier

    hallo2 *hip = new hallo2(h1, h2);
    

    Das ist C++. C hat kein new. Was du meinst ist low level C++.



  • out schrieb:

    asdsaddsasds schrieb:

    AnanasPilot schrieb:

    Wo mische ich denn C mit C++ ?

    Hier

    hallo2 *hip = new hallo2(h1, h2);
    

    Das ist C++. C hat kein new. Was du meinst ist low level C++.

    Ist es nicht das äquivalent zu (x)alloc?



  • asdsaddsasds schrieb:

    out schrieb:

    asdsaddsasds schrieb:

    AnanasPilot schrieb:

    Wo mische ich denn C mit C++ ?

    Hier

    hallo2 *hip = new hallo2(h1, h2);
    

    Das ist C++. C hat kein new. Was du meinst ist low level C++.

    Ist es nicht das äquivalent zu (x)alloc?

    Tatsächlich nicht. Zumindest zu dem malloc / free, wie ich es kenne.
    Mit new / delete wird der entsprechende Konstruktor aufgerufen und die nötigte Speichergröße automatisch bestimmt. Das hast du bei malloc und free nicht.



  • Schlangenmensch schrieb:

    asdsaddsasds schrieb:

    out schrieb:

    asdsaddsasds schrieb:

    AnanasPilot schrieb:

    Wo mische ich denn C mit C++ ?

    Hier

    hallo2 *hip = new hallo2(h1, h2);
    

    Das ist C++. C hat kein new. Was du meinst ist low level C++.

    Ist es nicht das äquivalent zu (x)alloc?

    Tatsächlich nicht. Zumindest zu dem malloc / free, wie ich es kenne.
    Mit new / delete wird der entsprechende Konstruktor aufgerufen und die nötigte Speichergröße automatisch bestimmt. Das hast du bei malloc und free nicht.

    Stimmt 👍 Ist bei mir schon etwas länger her, danke für die Erinnerung 😃



  • Danke für alle Antworten 🙂



  • asdsaddsasds schrieb:

    Dein Code verursacht deswegen ein Memory-Leak. Besser wäre folgendes

    #include <memory>
    #include <cstdlib>
    
    int main( int argc , char ** argv )
    {
      std::string h1( "1" );
      std::string h2( "2" );
    
      std::unique_ptr< hallo2 > hip( h1 , h2 );
      std::cout << hip->getHallo1() << std::endl;
    
      system( "pause" );
    
      return EXIT_SUCCESS;
    }
    

    den smart pointer kann man sich sparen:

    int main( int argc , char ** argv )
    {
    [...]
      hallo2 hip( h1 , h2 );
      std::cout << hip.getHallo1() << std::endl;
    [...]
    }
    


  • Sollte man sich sparen. Steht da hoffentlich auch nur, wegen des noch unsinnigeren news im Anfangspost.


Log in to reply