PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : komplett gekapseltes Delegate mit Parametern


mekakic
2012-03-15, 10:43:05
hi

ich grübel gerade etwas über der Möglichkeit einen konkreten Aufruf komplett zu kapseln. Ich habe dies hier gefunden: http://www.codeproject.com/Articles/13287/Fast-C-Delegate

Damit läßt sich einfach etwas realisieren was sonst unter C++ recht kompliziert ist. Einen Call auf eine Funktion und einen Member Function Pointer (scheußlicher Syntax:frown:) hinter dem Objekt eines Typs zu kapseln.

Kann man es aber auch irgendwie realisieren, dass man einen kompletten Call: also member function pointer und beliebiger Parameter unterschiedlicher Signatur in einem Delegate call verpacken kann. So daß der besitzer des Delegate Objekts nur ein delegate.invoke() machen muß und es wird die Methode inklusive der gespeicherten Paramter ausgeführt (die der ausführer nicht kennt).

Das Ziel ist es sogenannte Job-Objekte für Worker Threads zu verpacken und dort eine einheitliche Schnittstelle anzubieten. Sowas habe ich bisher immer in der Art gesehen, dass in den Call zwei Methoden und eine void* Schnittstelle eingeführt werden... mit vielem hin und her gecaste von structs und dem ein und auspacken der Daten. Das gefällt mir überhaupt nicht, aber eine Lösung habe ich dafür auch noch nicht gefunden. Kann sich jemand dazu was vorstellen?

Tiamat
2012-03-17, 11:22:11
Hi,

ein Delegate wird benutzt, um einen einen anderen Objekt eine Verantwortlichkeit zu übertragen. Das ist vor allem ein Strukturierungsmittel.

Was mich an diesem Fast-Delegate oder ultra fast Delegate Beispiel stört, ist das da aus irgendwelchen Gründen ein Objekt daraus gemacht wird.

Normalerweise hat man einen Supertyp in C++ eben eine abstrakte Klasse.

X.h(pp)
class X {

Supertyp *delegate;

void methode() {
..
if(delegate == NULL) {
// diese Klasse übernimmt diese Funktionalität
} else {
delegate.methode();
}
}
}


Wie sieht diese Supertyp Klasse aus


class Supertyp {
..
virtual void methode() = 0;
..
}


Jetzt benötigt man eben Klasse, die von Supertyp ableitet und die abstrakte Methode implementiert. Das ganze geht natürlich auch mit Parametern, die dann in dieser X Klasse übergeben werden.

Das sieht schon etwas anders aus, als dieses Fast-Delegate Beispiel, aber ich wüsste ehrlich gesagt, wieso hier ein Funktionszeiger oder gar ein Memberfunktionszeiger benötigt wird.

Master Worker ist ein ganz anderes Pattern. Hier werden Jobs(die man z.B im Objekten kapseln kann) an andere Rechenresourcen wie Threads oder Maschinen (z.b MPI) übergeben und vom Master verwaltet. Auch hier bedarf es vom Konzept her keinen Funktionszeigern oder Memberfunktionszeigern.

Gibt es irgendwelche speziellen Gründe, warum du das genau so (dein Beispiel) umsetzen willst, oder war dir der Unterschied nicht so klar ?

Gruß
Tiamat

Trap
2012-03-17, 11:48:39
ich grübel gerade etwas über der Möglichkeit einen konkreten Aufruf komplett zu kapseln.
Wenn du deinen Compiler aussuchen kannst sind Lambdas die einfachste Möglichkeit.

del_4901
2012-03-18, 12:20:17
Hi,

ein Delegate wird benutzt, um einen einen anderen Objekt eine Verantwortlichkeit zu übertragen. Das ist vor allem ein Strukturierungsmittel.

Was mich an diesem Fast-Delegate oder ultra fast Delegate Beispiel stört, ist das da aus irgendwelchen Gründen ein Objekt daraus gemacht wird.

Normalerweise hat man einen Supertyp in C++ eben eine abstrakte Klasse.

X.h(pp)
class X {

Supertyp *delegate;

void methode() {
..
if(delegate == NULL) {
// diese Klasse übernimmt diese Funktionalität
} else {
delegate.methode();
}
}
}


Wie sieht diese Supertyp Klasse aus


class Supertyp {
..
virtual void methode() = 0;
..
}


Jetzt benötigt man eben Klasse, die von Supertyp ableitet und die abstrakte Methode implementiert. Das ganze geht natürlich auch mit Parametern, die dann in dieser X Klasse übergeben werden.

Das sieht schon etwas anders aus, als dieses Fast-Delegate Beispiel, aber ich wüsste ehrlich gesagt, wieso hier ein Funktionszeiger oder gar ein Memberfunktionszeiger benötigt wird.

Master Worker ist ein ganz anderes Pattern. Hier werden Jobs(die man z.B im Objekten kapseln kann) an andere Rechenresourcen wie Threads oder Maschinen (z.b MPI) übergeben und vom Master verwaltet. Auch hier bedarf es vom Konzept her keinen Funktionszeigern oder Memberfunktionszeigern.

Gibt es irgendwelche speziellen Gründe, warum du das genau so (dein Beispiel) umsetzen willst, oder war dir der Unterschied nicht so klar ?

Gruß
Tiamat
Die Alternative mit dem Interface (Superclass) ist langsam, unflexibel und meist overengineered in seinem Beispiel. Delegates sind schon ne feine Sache wenn man Sie richtig einsetzen kann. Das Problem vom Topic-Ersteller hatte ich auch schon und ich kann mich erinnern in irgendeine Sackgasse gelaufen zu sein. Allerdings ist das schon ein paar Jaehrchen her und ich wuerde es nochmal versuchen wollen.

Gnafoo
2012-03-18, 15:45:33
Das klingt so, als ob du boost::bind und boost::function nachbauen willst.


#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>

struct A
{
void foo(int x) { std::cout << x << std::endl; }
};

void invoker(boost::function<void(void)> action)
{
// Verpackten Call ausführen.
action();
}

int main(int argc, char *argv[])
{
A a;

// Aufruf von foo() auf a mit Parameter verpacken und in action speichern.
boost::function<void(void)> action = boost::bind(&A::foo, boost::ref(a), 5);

// Verpackten Call an eine Funktion übergeben.
invoker(action);

return 0;
}

Tiamat
2012-03-18, 16:24:01
Ich wüsste nicht was da extrem langsam sein soll. Natürlich haben Design Pattern immer einen gewissen Overhead, dafür profitiert man ja in anderer Hinsicht(Struktur, e.t.c).

Unflexibel? Nein, denn jedes Delegate kann dank des Interfacedesigns spezifisch diese Funktionalität erfüllen. Dank Polymorphie können der Supertyp Class auch Subklassen des Typs zugewiesen gewiesen. Man könnte wenn man will auch Templaten.

del_4901
2012-03-18, 18:14:36
Ich wüsste nicht was da extrem langsam sein soll. Natürlich haben Design Pattern immer einen gewissen Overhead, dafür profitiert man ja in anderer Hinsicht(Struktur, e.t.c). Den vtable call wuerde ich vermeiden wollen wenn die Tasks klein sein koennen. Die zusaetzliche Struktur braucht man fuer ein Jobsystem nicht, das ist nur unnoetiger Schreibaufwand.

Unflexibel? Nein, denn jedes Delegate kann dank des Interfacedesigns spezifisch diese Funktionalität erfüllen. Dank Polymorphie können der Supertyp Class auch Subklassen des Typs zugewiesen gewiesen.Das sind Vorteile fuer das Delegate. Es ist Typsicher in bezug auf die Signatur und unabhaengig von jeder Klasse.
Man könnte wenn man will auch Templaten.Ja vllt. kann man was ueber CRTP drehen, aber das ist bestimmt tricky. Jeh nach Architektur muss man ja auch auf sein Speicherkontingent achten.