Functionsaufruf wenn Member in Klasse geändert
-
Thema verfehlt, würd ich sagen
-
@Redhead
das ist genau das Gegenteil von dem was ich möchte, aber denoch interessant und muß ich ja auch noch lernen.was ich will, ist sowas, wie Bashar schon sagte, __property. Das giebt es aber nur beim Borland Compiler, ich suche nach einer Lösung die mit Standard C++ zu realisieren ist um sowas zu ermöglichen. Hier mal Code Beispiel um zu Zeigen wie ich das meine:
/* >>> Bei Borland Compiler <<< */ class bccTest { private: int fWert; SetWert(int Wert) {if(Wert > 111)fWert = Wert;} public: __property int Wert = {read=fWert, write=SetWert}; }; /* >>> Welche Möglichkeit mit Standard C++ für sowas? <<< */ class cppTest { private: int fWert; public: int Wert; /* onWrite rufe Function auf, onRead gebe fWert zurück ??? */ /* void Set_Wert(int Wert); */ /* int Get_Wert(); */ /* Set_, Get_ kenne ich, und will ich verhindern, ich will wie bcc */ };
Der Sinn ist, leichter zu Arbeiten mit Klassen, die Atribute für z.B. Fenster und Controls haben, wie width, height, top, left etc.
So brauche ich nur instance->Width = 5 zu schreiben, und eine Function wird aufgerufen um diesen wert entsprechend an das Control zu übermitteln. Bei int wert = instance->Width wird der entsprechende Wert zurückgeliefert.
-
Einer_der_Lernt schrieb:
Der Sinn ist, leichter zu Arbeiten mit Klassen, die Atribute für z.B. Fenster und Controls haben, wie width, height, top, left etc.
So brauche ich nur instance->Width = 5 zu schreiben, und eine Function wird aufgerufen um diesen wert entsprechend an das Control zu übermitteln. Bei int wert = instance->Width wird der entsprechende Wert zurückgeliefert.weil
instance->Width(5) statt instance->Width=5 um 1 zeichen mehr zu tippen ist, oder was?es gibt keine properties in c++ und wirklich sinnvoll sind die borland properties auch nicht, die machen erst bei reflection wirklich sinn (weil man dann accessors von normalen methoden unterscheiden kann).
es gibt natürlich auch hacks um properties in c++ zu haben, macht aber idr keinen sinn.
-
Bau dir einen Proxy mit überladenem operator=, wenn du die Synthax so toll findet. Wunder dich aber nicht, wenn die Implementation der Klasse anschließend ziemlich unübersichtlich wird.
-
Und falls das von Helium jetzt noch nicht ganz klar ist:
template<class T> class clalling_proxy { private: T safed; vector<void(*)()> callbacks; public: const calling_proxy& operator=(T& t) { safed=t; call_all_callbacks(); }; void add_callback(void(*pf)()) { callbacks.push_back(pf); }; void remove_callback(void(*pf)()) { callbacks.erase(pf); //geht das? }; void call_all_callbacks() { for(unsigned i=0;i<callbacks.size();++i) callbacks[i](); }; };
Ist natürlich nach belieben erweiterbar...
-
Danke ness, aber mir ist nicht nur das von helium unklar, sondern deine Vorgabe auch, bzw. weiß ich nicht wie ich das verwenden soll, ich lerne ja noch.
Templetes sind mir schon bekannt, verstehe ich aber erst noch gering.
vektor kenn ich überhaupt nicht.wie gesagt, ich weiß nicht wie ich dein Beispiel in meiner Klasse für besagten Zweck verwenden soll.
-
Einer_der_Lernt schrieb:
Danke ness, aber mir ist nicht nur das von helium unklar, sondern deine Vorgabe auch, bzw. weiß ich nicht wie ich das verwenden soll, ich lerne ja noch.
Wenn du so weit bist, dass du das von Helium verstehst und umsetzen kannst, willst du es nicht mehr, weil du dich an die Gegebenheiten gewöhnt hast
Das Beispiel von ness ist eine Art Callback-Registrierung, mit dem was Helium gesagt hat hat das so gut wie nichts zu tun.
vektor kenn ich überhaupt nicht.
Solltest du aber, vector ist eine der wichtigsten Klassen der Standardbibliothek.
-
@Bashar
Deine Hinweise und Komentare in Ehren, aber anstelle mein Vorhaben zu Zerreden, wären Informationen zu meinen Fragen mir lieber. Wenn ich das habe was ich will, auch wenn es zusammen gebastelt ist oder gar ganz kopiert, dann kann ich das ganze besser Zeile für Zeile auseinander nehmen und lernen es zu verstehen, es kommt z.B. vector, oerator= (operator++.-- etc.) usw. vor, die ich somit besser erlernen kann, da ich weiß was das Endergebnis ist.Ich versuche mal den code von ness zu entschlüsseln, in wie weit ich es verstehe:
template<class T> /* wo folgend ein T steht, wird mit dem Klassennamen ersetzt, auch bei vererbung */ class calling_proxy { private: T safed; /* wäre dann calling_proxy safed; */ vector<void(*)()> callbacks; /* vector ist eine Art dynamisches Array, <void(*)()> speichert Functionszeiger */ public: const calling_proxy& operator=(T& t) { safed=t; call_all_callbacks(); }; /* wie die operator= function aufgerufen wird weiß ich nicht */ /* ich denke aber mal T->wert() = 5; (void wert() { ... } ist es nicht */ void add_callback(void(*pf)()) { callbacks.push_back(pf); }; void remove_callback(void(*pf)()) { callbacks.erase(pf); //geht das? }; /* die oberen setzten und entfernen Zeiger aus dem vector */ void call_all_callbacks() { for(unsigned i=0;i<callbacks.size();++i) callbacks[i](); }; /* der aufruf von operator=, hier werden alle Functionen die im vector sind aufgerufen */ };
wie ich das jetzt aber nutze damit eine Function aufgerufen wird, wenn der Member int wert; geändert wird, weiß ich nicht.
-
Sag mal, was spricht eigentlich genau dagegen, daß Du alle Änderungen an der Variable über setVariable(parameter) vornimmst und dort auch Deinen Benachrichtigungsaufruf unterbringst? Alles andere ist irgendwie hacky und genau darauf versucht Bashar Dich aufmerksam zu machen. Gerade weil Du noch einiges zu lernen hast ist es nicht sinnvoll eine Lösung zu verstehen zu versuchen die man nicht verwenden sollte.
MfG Jester
-
@Jester
es spricht nichts dagegen, ich verwendete bisher in allen lernprojekten get_variable() und set_variable(x), mit anderen Worten, es ist mir bekannt.
Meine suche war jetzt nach der Möglichkeit wie es Borland bietet, und es giebt diese Möglichkeit, also möchte ich diese gerne erlernen, wie man sieht ist es nicht einfach und es kommen dinge drinn vor die gleich mit erlene.
Sollte die Nutzung der Möglichkeit nicht Ratsam sein, kann es sein das ich das dann auch nicht nutze, aber ich weiß wie es geht und das gelernte kann ich sicherlich für andere Zwecke mal gebrauchen.zum Topic:
Ich habe das mal umgeschrieben um das mit template und operator= besser zu verstehen, mit vector taste ich mich dann langsam ran:#include <windows.h> #include <vector> using namespace std; template<class T> class _property { private: T safed; public: const _property& operator=(T t) { safed=t; }; /* ist folgendes der umgekehrte weg??? */ T operator=(_property&) { return safed; } }; class teste { public: _property<int> wert; }; //............. teste *test = new teste(); test->wert = 5;
Das Funktioniert auf jeden Fall, aber
int x = test->wert;
geht nicht (kein convert von _property<int> nach int),
ist der umgekehrte weg von mir richtig?
-
Warum hat mein Vorschlag mit dem was Helium sagt nix zu tun? Das ist doch n proxy mit überladenem operator=. Nur, wenn ich das Problem richtig verstanden habe, geht es doch darum Funktionen aufzurufen wenn der Wert geändert wird. Nur hat das wenig Sinn, wenn man so eine Funktion nicht registrieren kann... Wenn es nur um eine Funktion geht kann man die auch als template-parameter Verwenden, oder man benutzt Funktoren und interne Klassen, aber das sind alles Varianten. Hab ich da was komplett falsch verstanden?
Zur benutzung: (find ich auch doof, aber egal...)
class test { public: calling_proxy<int> wert; }; void mach_was() test.wert.add_callback(mach_was); test.wert=4; //der überladene operator= wird mit vier aufgerufen //mach_was() wird aufgerufen
So stell ich mir das jedenfalls vor...
-
So, ich habe in den letzten Stunden viel über template und operator überladung gelesen, ja toll schöne Sache, sicherlich mal zu gebarauchen, ich habe auch viel damit rum experimentiert. ABER
Nicht das was ich meine, ich kann nur die Operatoren für Klassen überladen, so habe ich Variablen die einer Klasse entsprechen:klasse a = test->b;
was ich aber möchte, ist ein Event, also Functionsaufruf wenn eine Variable geändert wird, nicht eine Klasse!
damit folgendes funktioniert:/* 1 */ int a = 7; /* 2 */ test->wert = a; //event - Function aufrufen /* 3 */ int b = test->wert; // ebenso /* 4 */ if (test->wert == b) /* etc. */ // hier auch (ist ja wie 3)
Klasse nach int casten geht nicht, und soll auch nicht der Sinn sein
- @helium, wenn deine Angabe dem entspricht mit Proxy, wie muß ich das dann machen.
- sollte functor etc. die einfachere Methode sein: was ist das, wie benutze ich sowas?
- wie kann ich nun das genau realisieren?@Bashar und Jester
wenn ihr wisst wie ich das realisieren kann, bitte ich euch mir zu helfen.
Das mag zwar nicht so toll sein, aber ich lerne immer mehr, wer hätte gedacht das ich heute Überladung und template lerne.
DankePS: <vector> ist wirklich nützlich und cool, beschäftige mich gerade nebenbei damit, <map> gefällt mir aber für manch viele Testprog. von mir am besten, bin durch vector drauf gekommen und guck mir beides genauer an.
-
Man kann per se keinen Code aufrufen lassen, wenn eine Variable eines Basistyps (int, etc.) geaendert wird. Ginge schon, bloss gibt's keinen Compiler dafuer, und keine C++ Spracherweiterung, die das unterstuetzen wuerde.
Du kannst aber folgendes machen:
#include <string> #include <stdio.h> typedef std::string String; template < class T > class MutiVar { public: typedef void (*CallbackHook)( MutiVar<T>& var ); T obj; String id; CallbackHook func; MutiVar( const String& _id, CallbackHook _func ) : id(_id), func(_func) { } // ... MutiVar<T>& operator=( const T& value ) { obj = value; func( *this ); } // ... }; // ... void Y_Callback( MutiVar<int>& var ) { printf( "variable %s has been modified to %d\n", var.id.c_str(), var.obj ); } void func( void ) { MutiVar<int> a( "Variable A", Y_Callback ); a = 5; }
In einer Klasse musst Du die Initialisierung der Variable natuerlich im Konstruktor machen.
class F { MutiVar<int> a; F( void ); }; F::F( void ) : a( "Variable A" ), Y_Callback ) { }
So geht's auf jeden Fall ohne groesseren Aufwand.
Auch wenn's nicht das ist, was Du haben wolltest!
-
Sooooo Freunde,
ich habe jetzt viel gelernt und meine eigenen Datenvariablen (class) gebastelt, funktioniert super, aber wie Bashar und Jester schon sagten, ist das nicht das tolle und ware und man sollte es auf der traditionalen Art machen, ala Getter und Setter (get_xxx(), set_xxx(value) ), doch ich brauche Ordnung, und für Windows mit seinen Controls verliert man schnell den Überblick, wenn die Eingabehilfe, bzw. Ergänzung z.B. bei der dev-cpp IDE, aufklappt.
Daher das ganze hier. Ich habe mir zu diesem Zweck was anderes einfallen lassen, eine Get Klasse und eine Set Klasse, so das ich alle getter in einer Klasse habe und alle Setter in einer Klasse:
ControlKlasse->Get->Width(), ControlKlasse->Set->Width(123)
Funktioniert auch super, hier mal eine Kurzform aus der Testphase:#include <windows.h> #define MYWINMOVE 77701 #define MYSETTEXT 77702 #define MYSETMENU 77703 #define MYSETICON 77704 /* u.s.w. etc. */ class parameter { public: HWND Handle; int Width; int Height; int Left; int Top; LPCSTR Caption; void UpdateControll(int type) { if (type == MYWINMOVE && Handle) MoveWindow(Handle,Left,Top,Width,Height,true); /* u.s.w. etc. */ } }; class getparam { private: parameter* param; public: getparam(parameter* p) {param = p;} ~getparam() {} int Width() {return param->Width;} }; class setparam { private: parameter* param; public: setparam(parameter* p) {param = p;} ~setparam() {} void Width(int width) { param->Width = width; param->UpdateControll(MYWINMOVE); } }; class test { private: parameter* param; public: getparam* Get; setparam* Set; test() { param = new parameter(); Get = new getparam(param); Set = new setparam(param); /* param->Handle = CreateWindow(....... */ } ~test() { delete param; delete Get; delete Set; } }; //............. // in WinMain: test* t = new test(); t->Set->Width(5); int x = t->Get->Width(); if (x == 5) MessageBox(NULL,"ok 5","info",MB_OK); t->Set->Width(8); x = t->Get->Width(); if (x == 8) MessageBox(NULL,"ok 8","info",MB_OK); // Test alles ok
Was halltet ihr davon?
-
enno-tyrant schrieb:
[code] int eingabe; cout << "Wert eingeben: "; cin >> eingabe; test2.(eingabe);
Hmm, was für eine Syntax ist denn das? Ist damit ein impliziter Konstruktoraufruf gemeint und der Punkt nur versehentlich reingerutscht?