Warum ist der Pointer nicht NULL?



  • class Body
    {
        //....
        public:
            Fuss GetCool()  // retourniert eine Kopie von _Cool
            {
                return _Cool;
            }
    
            // stattdessen:
    
            Fuss& GetCool()  // retourniert eine Referenz auf _Cool
            {
                return _Cool;
            }
    };
    


  • Danke!
    Sehe ich es richtig, das man immer Referenzen benutzen sollte und nie Kopien bei Methodenaufrufen?

    Foo.h

    #ifndef __Foo__
    #define __Foo__
    
    class Foo
    {
    	private:
    		wxString Test;
    
    	public:
    		void SetTest(wxString& inTest)
    		{
    			Test = inTest;
    		}
    
    	public:
    		wxString& GetTest()
    		{
    			return Test;
    		}
    };
    
    #endif
    

    EventHandler:

    virtual void OnButton1Click(wxCommandEvent& event)
    		{
    			Foo Blau;
    			Blau.SetTest("WessenBlau");
    
    			Button1->SetLabel(Blau.GetTest());
    		}
    

    Der Compiler scheint das & bei SetTest nicht zu mögen. Warum?
    Fehler: keine passende Funktion für Aufruf von »Foo::SetTest(const char [13])«



  • DarkBug schrieb:

    Sehe ich es richtig, das man immer Referenzen benutzen sollte und nie Kopien bei Methodenaufrufen?

    Nein, siehst du nicht richtig. Man sollte den Unterschied kennen und immer wissen, was man braucht. Außerdem solltest du dich mit der Bedeutung von const vertraut machen - davon fehlen ein oder mehrere in deinem Code.

    Foo.h

    #ifndef __Foo__
    #define __Foo__
    

    Schau nochmal, was seldon oben geschrieben hat. __Foo__ ist ein reservierter Bezeichner.



  • DarkBug schrieb:

    Sehe ich es richtig, das man immer Referenzen benutzen sollte und nie Kopien bei Methodenaufrufen?

    Ja, jedoch nur unter der Bedingung, dass eine Kopie teurer ist, als eine Referenzübergabe. Bei fundamentalen Typen und bei Typen, deren Größen im Bereich eines fundamentalen Typs liegen, nimmst du call-by-value, da eine Kopie hier billiger ist. Sprich sizeof(object)<=12 call-by-value, ansonsten call-by-ref.

    DarkBug schrieb:

    Der Compiler scheint das & bei SetTest nicht zu mögen. Warum?
    Fehler: keine passende Funktion für Aufruf von »Foo::SetTest(const char [13])«

    Blau.SetTest("WessenBlau"); erzeugt ein temporäres Objekt. Temporäre Objekte darfst du nur an eine const-ref binden. SetTest(const wxString& inTest) Abgesehen davon, man verwendet eigentlich immer const-ref. Das, das du momentan hast, wird in einem anderen Kontext verwendet, nämlich für out-Parameter. out-Parameter ermöglichen dir eine beliebige Anzahl return-Werte. In deinem Fall willst du aber keinen return-Wert, darum const-ref.

    Und noch was, doppelte Unterstriche sind glaube ich nicht erlaubt. __Foo__



  • Okay, ich habe mir nun mal das Schlüsselwort const angeschaut.

    const & für primitive Datentypen wie wxString, wxInt32, wxDouble etc.
    keinen zusatz für normale Klassen wie wxButton, wxFrame, wxSocketBase etc.
    Wenn ja warum nicht auch const &?

    & wenn die Methode das Objekt an der Aufrufstelle verändern soll
    * wenn die Methode das Objekt an der Aufrufstelle verändern soll
    und/oder wenn auf NULL geprüft werden muss
    sowie eventuell das Objekt gewechselt werden soll

    Stimmt das so?

    Referenzen muss man nicht wie Pointer mit delete irgendwie löschen, oder?



  • DarkBug schrieb:

    Stimmt das so?

    Es ist egal welche Typen im Spiel sind, das kann man so nicht verallgemeinern. Wenn Du einen wxButton "ohne Zusatz" übergibst, wird das Objekt kopiert, was entweder schiefgeht (wenn wxWidgets so vernünftig programmiert ist, dass sich Widgets nicht kopieren lassen) oder garantiert nicht das macht, was Du möchtest. const-reference Übergabe macht überall dort Sinn, wo ein Objekt nicht verändert werden soll, aber nicht kopiert werden kann oder die Kopie zu aufwändig ist. Und was ist mit einem "primitiven Datentypen", der an der aufgerufenen Stelle verändert werden soll?

    EDIT:
    Ich versuche mal, ein paar mögliche Szenarien sinnvoll zu umreissen.

    kein Qualifizierer   Ursprungsobjekt soll nicht verändert werden UND ( Kopie ist
                         erwünscht ODER die Kopie unaufwändig, z.B. für int, char, 
                         short, ... )
    const &              Objekt soll nicht verändert werden UND ( Objekt ist nicht
                         kopierbar ODER die Kopie unerwünsch oder aufwändig, z.B.
                         wxString, wxButton, ... )
    &                    Objekt soll verändert werden (Hier ein Hinweis: Man kann
                         auch Objekte, zu denen nur ein Zeiger existiert per 
                         Referenz übergeben, indem man sie dereferenziert. Man kann
                         auch Zeiger per Referenz übergeben, wenn man & und * kom-
                         biniert
    *                    Spezialfälle  :p
    

    Referenzen muss man nicht wie Pointer mit delete irgendwie löschen, oder?

    Du musst weder Referenzen noch Pointer mit delete löschen, sondern per new erstellte Objekte. Dass deren Adressen häufig in Pointern gespeichert werden, ist eine andere Sache. Aber auch hier hängt's vom Anwendungsfall ab. Wenn Du z.B. einen Pointer auf ein Objekt bekommst, welches Dir nicht gehört, solltest Du das mit dem Löschen tunlist bleiben lassen.



  • Danke für deine Mühe!
    Du sagst keinen Qualifizierer für z.B. int, char oder short. Also anscheinend für alle primitiven Datentypen. Zählt da auch std::string bzw. wxString dazu?

    Wenn dem so ist, würdest du in meinem Beispiel keine Referenzen und auch keine Pointer verwenden, korrekt?

    Foo.h

    #ifndef Foo_
    #define Foo_
    
    class Foo
    {
        private:
            wxString Test;
    
        public:
            void SetTest(wxString inTest)
            {
                Test = inTest;
            }
    
        public:
            wxString GetTest()
            {
                return Test;
            }
    };
    
    #endif // Foo_
    

    EventHandler:

    virtual void OnButton1Click(wxCommandEvent& event)
    {
        Foo Blau;
        Blau.SetTest("WessenBlau");
    
        Button1->SetLabel(Blau.GetTest());
    }
    

  • Mod

    Zeichenketten sind keine primitiven Typen und hinzu kommt noch, dass man in der Regel nicht weiß, wie lang sie sind (der Kopieraufwand kann also beliebig groß werden). Daher würde ich Zeichenketten nie durch Kopie weitergeben, außer ich brauche aus irgendeinem Grund unbedingt eine Kopie.



  • Ok.

    Foo.h

    #ifndef Foo_ 
    #define Foo_ 
    
    class Foo 
    { 
        private: 
            wxString Test; 
    
        public: 
            void SetTest(const wxString& inTest) 
            { 
                Test = inTest;
            } 
    
        public: 
            wxString GetTest() 
            { 
                return Test; 
            } 
    }; 
    
    #endif // Foo_
    

    In Zeile 12 wird der Wert der Referenz in die Variable Test gespeichert, oder wird nur die Referenz irgendwie kopiert?

    Wie benutze ich const bei GetTest? const wxString& macht hier ja keinen Sinn, da der Rückgabestring ja eh nicht verändert werden kann, die Membervariable aber schon. Wie verhindere ich das?


  • Mod

    DarkBug schrieb:

    In Zeile 12 wird der Wert der Referenz in die Variable Test gespeichert, oder wird nur die Referenz irgendwie kopiert?

    Ersteres.

    Wie benutze ich const bei GetTest? const wxString& macht hier ja keinen Sinn,

    Doch!

    da der Rückgabestring ja eh nicht verändert werden kann,

    😕 Häh? Warum nicht?

    die Membervariable aber schon. Wie verhindere ich das?

    Siehe oben. Außerdem sollte die ganze Methode gleich mit const sein. Also:

    const wxString& GetTest() const
    {
     return Test;
    }
    

    (Disclaimer: Alles unter der Voraussetzung, dass wxstring eine halbwegs "normale" Semantik hat. Bei diesen GUI-Frameworks weiß man ja nie…)



  • Das const nach der Methode heißt, das in dieser Methode keine Klassenvariablen verändert werden können, oder?
    Während des return-Vorgangs kann die Variable doch nicht verändert werden. Nur vor dem return in der Methode und nachher vom Aufrufer der Methode.

    Also würde ein

    wxString& GetTest() const
    {
     return Test;
    }
    

    doch reichen, oder?


  • Mod

    Nein, denn dann könnte Test schließlich vom Aufrufer über die Referenz verändert werden. Irgendwie habe ich das Gefühl, du hast Referenzen noch überhaupt nicht verstanden.



  • Jetzt habe ich das soweit verstanden.

    Das const rechts von einer Methode verhindert, das man in dieser Methode keine Membervariablen verändern kann, oder?



  • Ja. Es muss außerdem beachtet werden, dass innerhalb dieser Methode keine Methode aufgerufen werden darf, die nicht const-qualifiziert ist.



  • Gut. Ich habe meinen Code nun soweit angepasst. Ist das so nun korrekt?

    Foo.h

    #ifndef __Foo__
    #define __Foo__
    
    class Foo
    {
    	private:
    		wxString Test;
    
    	public:
    		void SetTest(const wxString& inTest)
    		{
    			Test = inTest;
    		}
    
    	public:
    		const wxString& GetTest() const
    		{
    			return Test;
    		}
    };
    
    #endif
    

    App.cpp

    #ifdef WX_PRECOMP
    #include "wx_pch.h"
    #endif
    
    #ifdef __BORLANDC__
    #pragma hdrstop
    #endif
    
    #include <wx/wx.h>
    
    #include "MainFrame.h"
    
    class App : public wxApp
    {
        public: virtual bool OnInit()
        {
            MainFrame* mfMainFrame = new MainFrame(0L);
            mfMainFrame->SetIcon(wxICON(MainIcon));
            mfMainFrame->Show();
    
            return true;
        }
    };
    
    IMPLEMENT_APP(App);
    

    MainFrame.h

    ///////////////////////////////////////////////////////////////////////////
    // C++ code generated with wxFormBuilder (version Sep  8 2010)
    // http://www.wxformbuilder.org/
    //
    // PLEASE DO "NOT" EDIT THIS FILE!
    ///////////////////////////////////////////////////////////////////////////
    
    #ifndef __MainFrame__
    #define __MainFrame__
    
    #include <wx/string.h>
    #include <wx/button.h>
    #include <wx/gdicmn.h>
    #include <wx/font.h>
    #include <wx/colour.h>
    #include <wx/settings.h>
    #include <wx/sizer.h>
    #include <wx/frame.h>
    
    #include "Foo.h"
    
    ///////////////////////////////////////////////////////////////////////////
    
    ///////////////////////////////////////////////////////////////////////////////
    /// Class MainFrame
    ///////////////////////////////////////////////////////////////////////////////
    class MainFrame : public wxFrame
    {
    	private:
    
    	protected:
    		wxButton* Button1;
    
    		virtual void OnButton1Click(wxCommandEvent& event)
    		{
    			Foo Blau;
    			wxString Eins = "Eins";
    			wxString Zwei = "";
    
    			Blau.SetTest(Eins);
    			Zwei = Blau.GetTest();
    
    			Button1->SetLabel(Zwei);
    		}
    
    	public:
    
    		MainFrame(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(500,300), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL);
    		~MainFrame();
    
    };
    
    #endif //__MainFrame__
    

    MainFrame.cpp

    ///////////////////////////////////////////////////////////////////////////
    // C++ code generated with wxFormBuilder (version Sep  8 2010)
    // http://www.wxformbuilder.org/
    //
    // PLEASE DO "NOT" EDIT THIS FILE!
    ///////////////////////////////////////////////////////////////////////////
    
    #include "MainFrame.h"
    
    ///////////////////////////////////////////////////////////////////////////
    
    MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
    {
    	this->SetSizeHints( wxDefaultSize, wxDefaultSize );
    
    	wxBoxSizer* BoxSizer1;
    	BoxSizer1 = new wxBoxSizer( wxVERTICAL );
    
    	Button1 = new wxButton( this, wxID_ANY, wxT("MyButton"), wxDefaultPosition, wxDefaultSize, 0 );
    	BoxSizer1->Add( Button1, 0, wxALL, 5 );
    
    	this->SetSizer( BoxSizer1 );
    	this->Layout();
    
    	this->Centre( wxBOTH );
    
    	// Connect Events
    	Button1->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::OnButton1Click ), NULL, this );
    }
    
    MainFrame::~MainFrame()
    {
    	// Disconnect Events
    	Button1->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::OnButton1Click ), NULL, this );
    
    }
    


  • *push*



  • Dein Foo.h sieht, bis auf den reservierten Bezeichner "__Foo__", gut aus.


Anmelden zum Antworten