Muss ich eine public-bool-Variable initialisieren? [gelöst]
-
Hallo Gemeinschaft,
heute plagt mich mal wieder ein eher triviales Problem: Muss ich im C++Builder eine bool-Variable initialisieren? In der Hilfe steht:
BCB-Hilfe schrieb:
...
Wenn Sie ein Objekt von statischer Lebensdauer nicht initialisieren, wird es per Voreinstellung initialisiert:
- Es wird auf 0 gesetzt, wenn es zu einem arithmetischen Typ gehört.
...Nun ist aber ein Bool kein arithmetischer Typ. Wenn ich jedoch public-bool-Variablen uninitialisiert in meinem Programm habe,
steht immer false drin, sofern sie nicht im Programm irgendwo gesetzt werden. Ist das Zufall?
Oder werden sie, weil sie von statischer Lebensdauer sind, immer mit false (0) initialisiert?
Ich finde nirgendwo einen Hinweis, wie es sich mit der Initialisierung von Bools verhält...MfG
-
Hallo
Letzendlich zählt bool doch zu den integren Typen, damit gilt die zitierte Regel.
Aber wirklich nur für Variablen mit static-Modifikator. Ohne static hingegen werden auch bool-Variablen nicht automatisch initialisiert.bis bald
akari
-
Danke für die aufschlussreiche Antwort. Wenn ich das richtig verstehe, ist auf eine so deklarierte Variable:
// Header: public bool bAFlag;
die zitierte Regel also nicht anwendbar, da ich die Variable nicht mit static modifiziert habe!?!
Daher sind die nicht initialisierten public-bool-Variablen immer nur zufällig false nach dem Start meines Programmes!?!
Oder verhält es sich so, dass Header-Variablen doch statisch sind? Ich hätte vielleicht dazusagen sollen,
dass es hier um das Hauptformular meiner Anwendung geht...
Dieses ist ja über die gesamte Programmlaufzeit existent,
dh. die Header-Variable ist auch immer existent (gewissermaßen statisch)!?!
-
Wenn Du mit Header-Variablen Klassenmember Deines Hauptforms meinst, (geht aus dem Codebeispiel nicht hervor weil der Doppelpunkt fehlt
) so sind diese nicht statisch. Am einfachsten in die Initialisiererliste mit aufnehmen.
-
Vielen Dank,
witte schrieb:
Wenn Du mit Header-Variablen Klassenmember Deines Hauptforms meinst, [...] so sind diese nicht statisch.
Ja, die meine ich - ich hab's geahnt!
witte schrieb:
... (geht aus dem Codebeispiel nicht hervor weil der Doppelpunkt fehlt
) ...
Heut' morgen mit Peter Lustig zusammen geduscht, was?
witte schrieb:
... Am einfachsten in die Initialisiererliste mit aufnehmen.
Meinst Du damit den Bereich im ctor wo ich alle Klassenmember initialisiere? Da stehen sie schon - Wollte mir nur gerne dieses lästige Initialisieren sparen...
MfG
Edit: Was ändert sich nun für mich, wenn ich die Variablen so deklariere (ausser das ich sie nicht mehr initialisieren muss):
// Header: public: static bool bAFlag;
Hätte das Nachteile?
-
Kommt drauf an... von statischen Variablen existiert nur eine Instanz, bei statischen member Variablen teilen sich alle Objekte der Klasse die statische Variable. D.h. wenn du mehrere Objekte eines Typs hast, und ein Objekt ändert den Wert der statischen Variablen von true auf false, dann ist der Wert für alle anderen Objekte ebenfalls false.
Ob das deinem Design entgegenkommt weiß ich nicht, aber in der Regel führt die Faulheit von Programmierern oft zu seltsamen Effekten, die zu beseitigen weit mehr kosten als das ursprüngliche Problem vernünftig zu lösen.Gruß,
Doc
-
Hallo
Grundlagen C++?!
static besagt das eine Member-Variable nur genau einmal für alle Klasseninstanzen vorhanden ist, nicht wie normal pro Instanz eine eigene.
Was ist denn so schlimm daran, grundsätzliche alle Variablen zu initialisieren und sich nicht auf mögliche Standardinitialierungen zu verlassen?
bis bald
akari
-
akari schrieb:
Grundlagen C++?!
static besagt das eine Member-Variable nur genau einmal für alle Klasseninstanzen vorhanden ist, nicht wie normal pro Instanz eine eigene.
Das war schon klar. Meine Frage nach Nachteilen zielt darauf ab, ob es weitere (nicht so bekannte) Faktoren gibt, die es bei der Verwendung von static zu beachten gilt!?!
akari schrieb:
Was ist denn so schlimm daran, grundsätzliche alle Variablen zu initialisieren und sich nicht auf mögliche Standardinitialierungen zu verlassen?
Gegenfrage: Wenn es nur eine Instanz der Klasse in meinem Programm gibt und static-Variablen standardmäßig initialisiert werden, wieso sollte ich dann den Konstruktor so aussehen lassen:
__fastcall TFormMain::TFormMain(TComponent* Owner) : TForm(Owner) { Application->HintColor= clKunterbunt; Application->HintHidePause= kurz; Application->HintPause= 1000; bBlaBlub= false; bNewBla= false; bBlaPop= true; bBlauGelb= false; bConfused= false; bAFlag1= false; bAFlag2= false; bAFlag3= false; bAFlag4= false; bAFlag5= false; bAFlag6= false; bAFlag7= false; BlaNbr= "x"; memset(DingDong, 0x00, 120); DingDong[60]= 0xBB; FastNr= ""; if(Screen->Width>=1024) { Label->Left= ((Screen->Width/100)*50); Label->Top= ((Screen->Height/100)*50); } else { Label->Left= ((Screen->Width/100)*20); Label->Top= ((Screen->Height/100)*20); } } //-----------------------------------------------------------------------------
wenn er auch so aussehen kann:
__fastcall TFormMain::TFormMain(TComponent* Owner) : TForm(Owner) { Application->HintColor= clKunterbunt; Application->HintHidePause= kurz; Application->HintPause= 1000; bBlaPop= true; BlaNbr= "x"; memset(DingDong, 0x00, 120); DingDong[60]= 0xBB; FastNr= ""; if(Screen->Width>=1024) { Label->Left= ((Screen->Width/100)*50); Label->Top= ((Screen->Height/100)*50); } else { Label->Left= ((Screen->Width/100)*20); Label->Top= ((Screen->Height/100)*20); } } //-----------------------------------------------------------------------------
???
Verstehe nicht, was daran das Problem ist?
-
Hallo
Eine Variable nur deshalb als static zu deklarieren um die Initialisierung zu sparen ist für schlechter Stil. Denn wie schon gesagt ist static ein eigenes Konzept.
Für dich mag dein "Trick" noch nachvollziehbar sein, für jemand anders der deinen Code durchsehen muß nur ein lästiges Rätsel.Um den Konstruktor auszuräumen solltest du wie schon gesagt die einfachen Initialisierungen in die Initialisierungsliste verschieben.
bis bald
akari
-
Gut, dann lass ich die Initialisierungen im ctor und fertig! Ob ich jetzt 'ne Init-Methode schreib'
(das ist doch mit Initialisierungsliste gemeint oder?) - spart auch keinen Code und macht das ganze nicht bequemer...Vielen Dank für Eure konstruktiven Antworten.
-
Eine Init()-Methode ist damit nicht gemeint. Such mal nach Initialisierliste.
-
Initialisierungslisten sind Vorgaben, mit denen Variablen bei ihrer Erzeugung initialisiert werden:
class MyClass { int Integer; double Double; public: MyClass() : Integer( 0 ), // <-- Initialisierungsliste Double( 0.0 ) // <-- dito { } MyClass( int iValue, double dValue ) { // keine Initialisierungsliste ! Integer = iValue; Double = dValue; } };
Eine zweistufige Initialisierung macht dann Sinn, wenn die Konstruktion eines Objektes teuer ist nicht bekannt ist, ob und wann auf Elemente der Klasse zugegriffen wird.
Gruß,
Doc
-
Moin Moin,
weiter geht's:
DocShoe schrieb:
Eine zweistufige Initialisierung macht dann Sinn, wenn die Konstruktion eines Objektes teuer ist nicht bekannt ist, ob und wann auf Elemente der Klasse zugegriffen wird.
Mit dem Satz kann ich mal garnix anfangen... und das nicht nur grammatikalisch!
So, den Konstruktor in der Main.cpp gibt's nun nicht mehr.
Ein paar Sachen hab' ich in die OnShow-Methode des Forms verschoben:
void __fastcall TFormMain::FormShow(TObjekt* Sender) { Application->HintColor= clKunterbunt; Application->HintHidePause= kurz; Application->HintPause= 1000; if(Screen->Width>=1024) { Label->Left= ((Screen->Width/100)*50); Label->Top= ((Screen->Height/100)*50); } else { Label->Left= ((Screen->Width/100)*20); Label->Top= ((Screen->Height/100)*20); } } //-----------------------------------------------------------------------------
Und in der Header-Datei hat jetzt einen Konstruktor mit Initialisierungsliste und Rumpf, der so aussieht:
class TFormMain : public TForm { __published: // Komponenten, die von der IDE verwaltet werden //... private: // Benutzerdeklarationen bool bFlagA, bFlagB; unsigned char ArrayA[520]; HANDLE hTest; bool FunctionA(int); bool FunctionB(int, int); bool FunctionC(); int FunctionD(); bool FunctionE(unsigned char, unsigned char, unsigned char, int); public: // Benutzerdeklarationen bool bFlagC, bFlagD, bFlagE; unsigned char ArrayB[120]; short sVarA; AnsiString StrA, StrB, StrC; bool FunctionF(int, int, int); bool FunctionG(); bool FunctionH(); bool FunctionI(); bool FunctionJ(); bool FunctionK(TObject *Sender); AnsiString FunctionL(); AnsiString FunctionM(); __fastcall TFormMain(TComponent* Owner): bFlagA(false), bFlagB(false), bFlagC(true), bFlagD(false), bFlagE(false), StrA(""), StrA("x") { memset(ArrayB, 0x00, 120); ArrayB[60]= 0xBB; } };
Das müsste es ja sein, dachte ich... das war mein Fehler: ich habe gedacht! Jetzt bekomm' ich folgende Fehlermeldung beim Compilieren:
[C++Fehler] Main.h(87): Cannot find default constructor to initialize base class 'Forms::TForm'.
Was habe ich falsch gemacht?
-
Hallo
Du sollst die Initialisierungsliste nicht ersetzen, sondern erweitern. Denn die Basisklasse TForm gehört als erstes dorthin, wo sie ja schon war.
__fastcall TFormMain(TComponent* Owner): TForm(Owner), bFlagA(false),...
Die Fehlermeldung besagt nichts weiter, als das der Compiler versucht mangels fehlender Angabe den parameterlosen Standardkonstruktor TForm() zu finden, den es aber nicht gibt.
Und warum hast du die Implementation des Konstruktor nun im Header? Du hättest die besser in der cpp-Datei lassen sollen.
bis bald
akari
-
Der vom Builder eingesetzte Kontruktor initialisiert seine Basis mit TForm(Owner), was Du hier einfach rausgelöscht hast.
-
Ach ja, wie dumm TForm(Owner) rausgelöscht... Besagt ja eigentlich die Fehlermeldung... mit den Fehlermeldungen stell' ich mich manchmal noch n bissl an... schon korrigiert, Danke!
akari schrieb:
Und warum hast du die Implementation des Konstruktor nun im Header? Du hättest die besser in der cpp-Datei lassen sollen.
Mir ist einfach nicht bewusst was daran schlecht ist... Kannst du dazu bitte etwas mehr sagen, ausser dass ich den Implementation des Konstruktors besser in der cpp gelassen hätte?
-
Hallo
Das betrifft erstmal das Konzept Datenkapselung. Headerdateien sind Teile von Schnittstellen, dort sollte nur das nötigste stehen was von außen kommende Zugriffe brauchen. Alle Implementationsdetails gehören in die cpp-Dateien (wenn möglich).
Das zweite ist einfach Praxis. Änderungen an Headerdateien erzwingen immer ein Neukompilieren alle davon abhängigen Übersetzungseinheiten (alle die die Headerdatei includen). Deshalb wirst bei bei großen Projekten froh sein, wenn du möglichst wenig in den Headerdateien stehen hast was geändert werden müßte.bis bald
akari
-
Ok, cool - klingt nachvollziehbar. Implementation des ctor ist inzwischen in der cpp gelandet.
Vielen Dank nochmal an Alle Beteiligten!
-
Hi Kolumbus,
hab mir gerade das Posting durchgelesen, das du nicht verstanden hast. Muss mich wohl beim Umformulieren des Satzes etwas, äh, verheddert haben. Manchmal eine Grammatik wie ein griechischer Gemüsehändler ich habe, junger Padawan.
Aber jetzt im Ernst:
Wenn die Konstruktion eines Objektes teuer im Sinne von zeitaufwändig ist, z.B. wenn langwierige Berechnungen zur Bestimmung von Daten durchgeführt werden müssen, dann kann eine zweistufige Konstruktion durch eine private init() Methode Sinn machen. Angenommen eine Klasse hat komplexe, langwierig zu bestimmende, aber auch triviale Eigenschaften. Wenn man die komplexen Daten nicht braucht, macht es keinen Sinn, sie bereits im Konstruktor zu bestimmen, sondern erst beim ersten Zugriff auf diese Daten. Dieses Beispiel sollte das ganz gut veranschaulichen:class ComplexObject { ComplexData Data_; unsigned int TrivialInt_; bool Initialized_; public: ComplexObject() : TrivialInt_( 1 ), // Integer mit 1 initialisieren Initialized_( false ) // komplexe Eigenschaft noch nicht initialisiert { } unsigned int get_int() const { // Zugriff auf triviale Eigenschaft return TrivialInt_; } ComplexData get_complex() const { // Zugriff auf komplexe Daten if( false == Initialized_ ) { // Daten werden zum ersten Mal angefragt, Bestimmung durchführen init(); } return Data_; } private: void init() { // führe Bestimmung der komplexen Eigenschaft durch // ... // Objekt jetzt vollständig initialisiert Initialized_ = true; } };
Das Ganze firmiert unter lazy initialization, glaube ich.
Gruß,
Doc
-
DocShoe schrieb:
Das Ganze firmiert unter lazy initialization, glaube ich.
Oder auch als Virtual-Proxy-Pattern.