Änderungen von Variablen in Variable speichern
-
Hallo zusammen ich bastel grad mit MFC an einigen (vielen) Editfeldern rum..
Wolllte wissen wie ich am besten speichere ob und was sich in den Feldern geändert hat.
hatte daran gedacht alles in nem short int zu speichern mit#define FELD1 (1<<0) #define FELD2 (1<<1) ... //vergleichen und speichern mit short int wAenderungen; if(Feld1.GetText() != davor.Feld1) wAenderungn = FELD1; if(Feld2.GetText() != davor.Feld2) wAenderungn = FELD2; ... // dann abrufen mit if(wAenderungen != 0) { if(wAnderungen & FELD1) //1.Feld geändert if(wAnderungen & FELD2) //2.Feld geändert }Da ich mich ja weiterbilden will
wollt ich wissen ob es da noch etwas eleganteres gibt.Gruß Has3
-
Has3 schrieb:
...
hatte daran gedacht alles in nem short int zu speichern mit
...Vergiß das lieber....

Erzeugt viel Aufwand und Fehlerrisiken und bringt kaum was. (was machst Du, wenn Du eine Variable mehr hast, als Bits in einem short ? Oder die Variablen ihre Reihenfoge verändern ? Wieviele Bits hat ein short auf der jeweiligen Compilerversion/PLattform/... ? ....)Du kannst einfach jeder Variable ein "bool" spendieren, in dem Du Dir das merkst ....
Und selbst das ist vermutlich überflüssig: Wofür brauchst Du denn überhaupt die Information, welche Daten sich geändert haben ?
Reicht da nicht ein vorher-nacher-Vergleich ?
Wenn es Dir nur darum geht, den Fall, dass sich gar nichts geändert hat, "wegzuoptimieren", solltest Du Deinem Dialog einfach einen "Cancel"-Button spendieren und fertig.Ach ja: so ein #define ist ziemlich "unschön" ....
Gruß,
Simon2.
-
Has3 schrieb:
//vergleichen und speichern mit short int wAenderungen; if(Feld1.GetText() != davor.Feld1) wAenderungn = FELD1; if(Feld2.GetText() != davor.Feld2) wAenderungn = FELD2; ...brauchst nicht die strings zu prüfen. edit-controls haben ein 'modified' flag.
--> CEdit::GetModify()Simon2 schrieb:
Ach ja: so ein #define ist ziemlich "unschön" ....

-
vista schrieb:
...
Simon2 schrieb:
Ach ja: so ein #define ist ziemlich "unschön" ....

zu Recht confused ... war ich nämlich auch. Ich habe im Ausdruck
1<<0das erste Zeichen als "kleines L" gelesen .... und nicht verstanden.Zwar stehe ich für Bitmuster immer noch die Hexdarstellung vor, aber trotzdem ziehe ich meinen Einwand zurück: "Unschön" ist das nicht.
Gruß,
Simon2.
-
wollte sehen ob man was in den Feldern abgeändert hat und wenn dann die Änderung in ner yesnochancel Messagebox anzeigen.
Is egentlich praktischer wenn ich erst ne Abfrage starte OB sich was geändert hat , falls dann die Messagebox anzuzeigen und auf den Inhalt einzugehen.
vista schrieb:
brauchst nicht die strings zu prüfen. edit-controls haben ein 'modified' flag.
--> CEdit::GetModify()nice to know : )
btw nich dass jmd das hier anschaut und falsch macht
es heißt |=short int wAenderungen = 0; if(Feld1.GetModify()) wAenderungn |= FELD1; if(Feld2.GetModify()) wAenderungn |= FELD2; ...
-
Has3 schrieb:
Da ich mich ja weiterbilden will
wollt ich wissen ob es da noch etwas eleganteres gibt.Ja, man kann da ein kleines Template bauen, welches jede Änderung registriert - etwa sowas
#include <iostream> #include <string> template< typename T > class Value { public: Value( const T& x ) : m_x( x ) , m_changed( false ) {} Value& operator=( const T& x ) { if( x != m_x ) { m_x = x; m_changed = true; } return *this; } bool hasChanged() const { return m_changed; } T get() const { return m_x; } void reset() { m_changed = false; } private: T m_x; bool m_changed; }; int main() { using namespace std; Value< string > feld1 = "Hallo"; feld1 = "Hallo"; if( !feld1.hasChanged() ) cout << "keine Änderung " << endl; feld1 = "Welt"; if( feld1.hasChanged() ) cout << "jetzt hat sich der Wert verändert " << endl; return 0; }Wenn notwendig, lässt sich Value<> natürlich aus so erweitern, dass sich der letzte Wert gemerkt wird. Der Zugriff auf den eigentlichen Wert geht mit get() (s.o.).
Gruß
Werner
-
Simon2 schrieb:
trotzdem ziehe ich meinen Einwand zurück: "Unschön" ist das nicht.
Wieso so zimperlich? '#define' für Konstanten ist grundsätzlich unschön.
-
Konrad Rudolph schrieb:
Simon2 schrieb:
trotzdem ziehe ich meinen Einwand zurück: "Unschön" ist das nicht.
Wieso so zimperlich? '#define' für Konstanten ist grundsätzlich unschön.
Weil ich meine Abneigung (die ich immer noch verspüre) in diesem Fall nicht konkret begründen kann. Ich hätte es anders gemacht ... aber nicht von Kollegen verlangt, es anders zu machen. Ursprünglich hatte ich diesen konkreten Fall für riskant empfunden ... jetzt bleibt nur die allgemeine Abneigung gegen #defines.
Gruß,
Simon2.
-
Werner Salomon schrieb:
Has3 schrieb:
Da ich mich ja weiterbilden will
wollt ich wissen ob es da noch etwas eleganteres gibt.Ja, man kann da ein kleines Template bauen, welches jede Änderung registriert - etwa sowas...
wie schon erwähnt: edit-controls kann man fragen, ob sich was verändert hat.
so elegant ein template sein mag (templates zu nutzen ist ja irgendwie immer elegant
), aber funktionalität nachzubauen, die schon existiert, ist niemals elegant.Simon2 schrieb:
Konrad Rudolph schrieb:
Simon2 schrieb:
trotzdem ziehe ich meinen Einwand zurück: "Unschön" ist das nicht.
Wieso so zimperlich? '#define' für Konstanten ist grundsätzlich unschön.
Weil ich meine Abneigung (die ich immer noch verspüre) in diesem Fall nicht konkret begründen kann.
kann es denn der Konrad begründen?

-
vista schrieb:
Simon2 schrieb:
Konrad Rudolph schrieb:
Simon2 schrieb:
trotzdem ziehe ich meinen Einwand zurück: "Unschön" ist das nicht.
Wieso so zimperlich? '#define' für Konstanten ist grundsätzlich unschön.
Weil ich meine Abneigung (die ich immer noch verspüre) in diesem Fall nicht konkret begründen kann.
kann es denn der Konrad begründen?

Ich denke, das kann er. Es gibt in C++ (im Gegensatz zu C) ein Sprachelement, welches das Definieren von Konstanten erlaubt. Damit gibt es keinen Grund mehr, auf den Präprozessor auszuweichen, welcher mehrere Nachteile hat:
- (a priori) keine Typensicherheit,
- zerstört die Logik des Programms und erschwert das Debuggen,
- stellt prinzipiell keinen konstanten Wert dar (s. Beispiel 1),
- ist fehleranfällig (z.B. durch vergessene Klammern, Beispiel 2),
- last, but not least: Zerstört Namensbereich-Zuordnungen und ist somit destruktiv.// So macht man es in C++: namespace math { const double pi = std::atan(1.0) * 4.0; } // So macht man es nicht. // Beispiel 1, wird jedes Mail neu berechnet, wenn der Code benutzt wird: #define pi (std::atan(1.0) * 4.0) cout << pi << endl; // Wert wird berechnet cout << pi << endl; // Wert wird erneut berechnet. // Beispiel 2, hier ham' wir den Salat. #define drei 2 + 1 cout << drei * 4 << endl;
-
Konrad Rudolph schrieb:
#define pi (std::atan(1.0) * 4.0) #define drei 2 + 1du hast es absichtlich falsch gemacht. damit kannst du niemanden überzeugen.
#define pi 3.1415926536 #define drei (2 + 1)nun sind die fehler weg.

-
gut zu wissen

werd mir mal das template anschaun wenn ich zeit hab.vielen Dank für die Hilfe
-
// irgendwo in den Weiten der Headers der vielen Libraries... // x1.h void drei(); enum { pi };// eigene header // A1.h #define pi 3.1415926536 #define drei (2 + 1)#include <eine_header_die_irgend_eine_header_X1_includiert.h> #include "A1.h" void foo() { int i = drei * pi; }Viel Spass bei der Fehlersuche!!!!!

-
vista schrieb:
du hast es absichtlich falsch gemacht. damit kannst du niemanden überzeugen.
Bei der Verwendung von PI ist mir eine exakt berechnete Version auf jeden Fall lieber als ein fest vorgegebener Wert (klar, für die meisten Anwendungen reicht sogar 3.14, aber sag das mal einem Puristen :D). Und ansonsten zeigen die Beispiele recht deutlich die Probleme des Präprozessors - #define ist eine dumpfe Textersetzung und wenn dabei Fehler auftreten, kannst du die nur schwer lokalisieren.
In C war #define womöglich noch verwendbar, aber in C++ ist es in den meisten Fällen unnötig (da gibt es Möglichkeiten mit vergleichbarer Anwendbarkeit, aber ohne die Schwächen des Präprozessors).
-
vista schrieb:
Konrad Rudolph schrieb:
#define pi (std::atan(1.0) * 4.0) #define drei 2 + 1du hast es absichtlich falsch gemacht.
Natürlich. Ich sagte ja auch, es sei fehleranfällig. Was glaubst Du, wie häufig diese Klammern vergessen werden!
damit kannst du niemanden überzeugen.
Jedem das seine. Aber in großen Teamprojekten ist man über jede eliminierte potentielle Fehlerquelle froh.
Natürlich kann man auch mit #defines's fehlerfreien Code schreiben, das habe ich nicht bestritten. Aber es ist definitiv schwerer, als wenn man es sein lässt.
#define pi 3.1415926536Ich bevorzuge die Definition über den Arkustangens.
-
ok, dass #define grundsätzlich fehlerträchtiger ist als etwas anderes kann ich nicht nachvollziehen, denn meistens handelt man sich fehlerquellen durch falsche anwendung ein und das kann auch mit anderen konstrukten passieren.
..und dass #define immer eine stumpfe textersetzung macht ist auch nicht ganz richtig. etwas rechnen kann es ja auch.
aber da ich von C++ null plan habe (ich programmiere meistens C), schenke ich euch mein blindes vertrauen und glaube euch, dass es in C++ andere möglichkeiten gibt, die besser ins konzept der sprache passen und die man als C++ progger deshalb #define vorziehen sollte.

-
vista schrieb:
..und dass #define immer eine stumpfe textersetzung macht ist auch nicht ganz richtig. etwas rechnen kann es ja auch.
Echt? Das beste, was der Präprozessor "rechnen" kann, sind die Operatoren # und ##. Bei einem
#define drei (1+2)wird jedes Vorkommen von 'drei' textuell ersetzt, ohne daß der Präprozessor sind den Inhalt der Ersetzung ansieht - der Rest ist dann Sache des Compilers (der die Berechnung von (1+2) rausoptimieren kann).
-
CStoll schrieb:
vista schrieb:
..und dass #define immer eine stumpfe textersetzung macht ist auch nicht ganz richtig. etwas rechnen kann es ja auch.
Echt? Das beste, was der Präprozessor "rechnen" kann, sind die Operatoren # und ##. Bei einem
#define drei (1+2)wird jedes Vorkommen von 'drei' textuell ersetzt, ohne daß der Präprozessor sind den Inhalt der Ersetzung ansieht - der Rest ist dann Sache des Compilers (der die Berechnung von (1+2) rausoptimieren kann).ich kann mich jetzt täuschen, aber als ich mir mal c-code nach dem preprocessor-durchlauf angeschaut habe (war' s jetzt beim codewarrior?)
da wurde so etwas:#define drei (1+2) ... int x = drei;das:
int x = 3;mag aber sein, das in der regel die präprozessoren nicht so schlau sind...

-
Der Compiler macht eine 3 draus, wenn er das sieht. Aber nicht der Präprozessor. Und ja, du hast von C++ keinen Plan, sonst würdest du das nicht so in deinem jugendlichen Leichtsinn sagen, das Makros nicht so übel sind. Denn du mußt dir einem bewusst werden:
static const int hallo = 2;Das Ding verbraucht KEINEN Speicher. (außer der Compiler ist so dämlich, aber dann würde ich den nicht weiter benutzen) Ich habe also nicht nur wie Makros keinen Speicherverbrauch, sondern auch noch ein Sprach-Element in Gebraucht. Ich kann das Hallo sogar in einen Namespace legen. Das geht alles nicht mit Makros. Es gibt KEINEN Grund dafür, wenn man C++ programmiert.
-
Artchi schrieb:
static const int hallo = 2;Das Ding verbraucht KEINEN Speicher.
demnach müsste ein 'sizeof(hallo)' 0 ergeben.
ist es so?
wäre jedenfalls unlogisch wenn nicht...
