Warum ist der Pointer nicht NULL?
-
Ist das nur mit Referenzen möglich? Zeige mir bitte am Codebeispiel, wie diese korrekt eingesetzt werden müssen.
-
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; } }; #endifEventHandler:
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
constvertraut 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)<=12call-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 sollStimmt 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 :pReferenzen 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()); }
-
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?
-
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?
-
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; } }; #endifApp.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.