Wie Signal aus Instanz einer Klasse an Instanz anderer Klasse schicken ?
-
Hallo Forum .. ich habe folgendes Problem :
Es soll für 3 verschiedene Schnittstellen ein Algorithmus geschrieben werden. Diese wahrscheinlich noch öfters. Nun würde ich gerne nicht jedesmal alles neu schreiben müssen sondern mir gerne 3 Interfaceklassen schreiben, die dann immer den selben Algorithmus aufrufen.
Mein Lösungsansatz sieht nun so aus :
Es gibt die Algorithmus-Klasse A und die 3 Interface-Klassen I1, I2, I3, diese Interface Klassen sind vererbte Klassen aus dem jeweiligem SDK des Interfaces.
Die jeweilige Interface-Klasse bekommt die A Klasse als Eigenschaft und die jeweiligen spezifischen Interfaceaufrufe werden auf die Aufrufe der A Klasse verteilt. So weit so gut ... wenn ich nun aber von der A Klasse etwas an die jeweilige Interfaceklasse übergeben will ohne das die Interface-Klasse eine Funktion A Klasse aufruft, sprich ich eine Funktionsrückgabe nutzen kann ...
Ich kann die jeweilige Interface-Klasse der A Klasse nicht bekannt machen, da es sich ja um 3 verschiedene Klassen handeln kann und dann es zu einem Überkreuz-Includen kommen würde.Wie wäre der beste Lösungsansatz ? Die ist bestimmt ein schon oft gelöstes Problem.
mfg ploenne
Ach so ... das ganze in c++ ohne Betriebssystemspezifische Librarys
-
Der Algorithmus wird wohl eine Funktion in irgendeiner Form sein. Deren Interface würde ich so generell halten, dass Du den Algorithmus auf jeden Fall mit den von Ihm benötigten Daten füttern kannst.
Dann kannst Du Wrapper schreiben, die die Aufrufe für die verschiedenen Schnittstellen überladen.void derAlgorithmus(some_types input_putput) { //... } void useAlgo(InterfaceA a) { derAlgorithmus(a.bla, a.pups, a.furtz); } void useAlgo(InterfaceB b) { derAlgorithmus(b.aha, b.weissnicht, b.nochwas); } void useAlgo(InterfaceC c) { derAlgorithmus(c.boaey, c.knall, c.sabbel); }Dabei hat
derAlgorithmusimmer die selbe Schnittstelle. Die Wrapper-Aufrufe biegen die spezifischen Schnittstellen auf diederAlgorithmus-Schnittstelle um.
-
Also das jeweilige Interface ist eine vererbte Klasse ... diese übergibt das Daten zum berechnen an den Algorithmus ... nun muss der Algorithmus ab und an etwas an das Interface zurückmelden ... kennt aber die Klasse nicht und ist dessen Eigenschaft.
Gut wäre ein Art Funktionspointer der auf einer Rückruf Funktion des jeweiligen Interfaces zeigt und dann im Falle des Falles diese Funktion der unbekannten Klasse aufruft.In C# würde ich der A Klasse ein Event verpassen und diesen von der Interface Klasse nach dem erzeugen der A Klasse abonnieren.
Die A Klasse will dem Interface was sagen ... ruft den Event auf ... der landed beim Interface. Zack fertig ... gibt es ein pendant dazu bei c++ ?danke ploenne
-
Du könntest die drei Klassen I1, I2, I3 verbinden, indem du eine gemeinsame Basisklasse mit virtueller Funktion verwendest. A enhält dann einen Zeiger auf diese Basisklasse.
struct Base { virtual void eventHappend()=0; }; struct A { Base *pBase; void startCalculation() { //Berechnung pBase->eventHappend(); } }; struct I1 {}; struct I2 {}; struct I3 {}; struct Interface1: public I1, public Base { void eventHappend(){ cout << "Interface 1: event noticed" << endl; } }; struct Interface2: public I2, public Base { void eventHappend(){ cout << "Interface 2: event noticed" << endl; } };Mit I3 dann dasselbe ...
-
Ich finde unter C++ oftmals auch Events schöner als Methodenaufrufe auf Interfaceklassen, die einem Eventhandler entsprechen. Das ist auch mein größter Kritikpunkt an C++, dass man in dem Fall C++ echt dazu überreden muss, sowas zu unterstützen und dann irgendwelche kryptischen Fehlermeldungen bekommt, wenn man einen simplen Fehler begangen hat. Naja, ich setze da auf den neuen Standard, mit seinen erweiterten Möglichkeiten für templates.
Schau dir auf jeden Fall mal boost::signals oder sigc++ an!
PS: Ich hab mich natürlich nicht mit deinem genauen Problem beschäftigt und weiß nicht ob das hier überhaupt sinn macht

-
Hi ploenne,
warum in aller Welt sollen Klassen herhalten für die Modellierung eines Algorithmus ?
Wie schon Tachyon anregte, sind Funktionen ideal dafür.
Was spricht gegen den Ansatz von Tachyon?
Außerdem habe ich den Eindruck, dass Du dieser Aufgabe mit Klassen und "Events" zuleibe zu rücken versuchst, weil Du "das immer so gemacht hast"... Ich sehe gar nicht, wo ein Algorithmus irgendein "Event" bräuchte - außer evtl. zu Zwecken der technischen Ablaufsteuerung (Abbruch, Fortschritt, ....), von denen Du aber nicht zu reden scheinst.
Ist nicht böse gemeint, sondern soll nur helfen.Außerdem ist gut möglich, dass ich Deine Aufgabenstellung nicht richtig verstanden habe (da ging es von der sehr knappen Aufgabenbeschreibung sehr ruckartig in Deinen ausgefeilten Lösungsansatz über ... ohne dass ich da allzu viele Verbindungsstücke gesehen hätte
).Gruß,
Simon2.
-
Also nochmal genauer :
Geschrieben werden soll ein PlugIn ... das in verschiedenen Hosts laufen soll.
Host A erwartet als PlugIn eine (vererbte) Klasse vom Typ I1 (I1 stammt aus dem SDK des Host A).
Host B erwartet als PlugIn eine (vererbte) Klasse vom Typ I2 (I2 stammt aus dem SDK des Host B).
Host C erwartet als PlugIn eine (vererbte) Klasse vom Typ I3 (I1 stammt aus dem SDK des Host C).Das ist auch der Grund warum die Interfaces auf keinem Fall der selben Basisklasse angehören können.
Intern macht das PlugIn immer den selben Job, z.B. bekommt ein Array von Farbwerten übergeben und multipliziert die Farbwerte mit einem Faktor X.
Die Funktionsaufrufe der PlugIns heissen zwar nicht gleich, aber aber alle ähnliche Funktionen ... das würde ich dann in den Interfaces auf mein standard plugIn angleichen und bräuchte mich künftig nur noch das interne Prozessing (in diesem Fall die Multiplikation) zu kümmern.
Nun passiert es aber auch das das PlugIn Informationen an den Host weitergeben muss, z.B. wenn der Benutzer eine Eingabe auf der PlugIn Oberfläche macht ... der Benutzer verändert den Faktor X ... das PlugIn müsste nun den Host auffordern die aktuellen Farbdaten erneut zu schicken um das Prozessing erneut durchzuführen. Von der jeweiligen Interface Klasse ist dies kein Problem, die Hosts haben die jeweiligen Aufrufe parat.
Ja ich habe sowas öfters schon mit Events gelöst, fand ich auch einen passenden Ansatz dafür ... aber der Post ist ja dafür da mich auch auf andere Lösungsansätze zu bringen.
Vielleicht erklärt dies das Problem besser. Ich werde mit mal Boost zu Gemüte ziehen.
-
Mir fallen spontan zwei Möglichkeiten ein:
A)
Du schreibst Ableitungen von I1, I2, I3, nennen wir sie mal J1, J2, J3, die einen Pointer/eine Referenz auf deinen Pluginkern haben (den der die Mutliplikation macht), und die die verschieden benannten Funktionsaufrufe der Interfaces in die Aufrufe des Pluginkerns übersetzt. Für die Rückaufrufe leiten J1, J2, J3 außerdem von einer gemeinsamen Basisklasse ab (JBase), in der die möglichen Rückaufrufe pur virtuell deklariert sind. J1, J2, J3 implementieren sie in entsprechende Aufrufe an den jeweiligen Host. Der Pluginkern hält einen Pointer auf JBase (hinter dem dann in Wirklichkeit ein entsprechender J1, etc. sitzt) über den er die Rückaufrufe triggern kann.
Bei Möglichkeit A sind also die Methoden in den Jx so gut wie alle virtuell, die vom Pluginkern nicht.
Die Jx leiten nur von den Ix ab, haben aber außerdem in den meisten Fällen Funktionen für die Rückaufrufe, die in allen Jx gleich aufgerufen werden können. Der Pluginkern ist ein Klasentemplate das von einer Basisklasse erbt. Der Templateparameter ist jeweils eine Jx-Klasse. Jx halten einen Pointer auf die Basisklasse, der jeweilige Pluginkern hält einen Pointer auf sein Jx. In dem Fall wird der Kern über das Basisklasseninterface aufgerufen, die Rückaufrufe geschehen über die Jx-Methoden - da es sich um Templateargumente handelt müssen die Jx nicht in der gleichen Klassenhierarchie sein (statische Polymorphie). Der Vorteil gegen Ansatz A ist, dass man den Kern im Notfall für bestimmte Hosts (bzw. für die entsprechenden Jx) spezialisieren kann. Der Nachteil ist, dass die Methoden der Pluginkerne virtuell sind.