Was ist Versand? Bedeutet dies eine dynamische Auflösung?

8

AFAIK, der Begriff Versand bedeutet nur eine Methodenauflösung und einen Aufruf. Es spielt keine Rolle, ob es statisch oder dynamisch ist. Ich habe gesehen, dass viele Leute einen Begriff wie statischen Versand und dynamischen Versand verwenden .

Was mich verwirrt, ist, dass es auch einige mysteriöse Beschreibungen gibt. Ich habe versucht zu verstehen, was Mehrfachversand ist , und es scheint, als würde nur ein Unterprogramm nach Parametertypen ausgewählt . Wenn ich es richtig verstanden habe, kann es sowohl statischen Mehrfachversand als auch dynamischen Mehrfachversand geben , und wir können sagen, dass C ++ Mehrfachversand über kostenlose Funktionen bereitstellt .

In einem Wikipedia-Artikel über Mehrfachversand heißt es jedoch, dass C ++ keinen Mehrfachversand hat, da es keine dynamische Auflösung der Funktion durch mehrere Parameter hat. Und ich bekomme wirklich keinen konzeptionellen Unterschied zwischen dem Common Lisp-Beispiel und der überladenen C ++ - Funktion. Weil ich keinen konzeptionellen Unterschied finden kann, wenn der Begriff Mehrfachversand keinen dynamischen Versand impliziert . Und mir wurde klar, dass ich verwirrend bin, was der Versand wirklich ist

Ich habe auch den QS-Eintrag Multiple Dispatch vs. Function Overloading überprüft , und es scheint, dass die Antwort davon ausgeht, dass der Begriff Dispatch grundsätzlich dynamisch ist . Das macht mich auch verwirrend.

Was bedeutet der Begriff Versand richtig ? Bedeutet dies eine dynamische Auflösung ? Ist dieser Begriff gut definiert oder nur konventionell? Was vermisse ich?

Eonil
quelle
1
"In einem Wikipedia-Artikel über Mehrfachversand heißt es, dass C ++ keinen Mehrfachversand hat" - auf welchen Artikel beziehen Sie sich? C ++ hat mehrere Versendungen. Und ja, Mehrfachversand bedeutet Dynamik (siehe en.wikipedia.org/wiki/Multiple_dispatch )
miraculixx
@miraculixx Das ist der Artikel. Und der Wikipedia-Artikel erwähnt keine statischen / dynamischen Attribute, daher war ich völlig verwirrt.
Eonil
1
@miraculixx - C ++ hat keinen Mehrfachversand. Sie müssen es mit einem Designmuster wie dem Besuchermuster fälschen.
David Hammen
@ David in der Tat, ich glaube, ich war dort selbst verwirrt und habe für einen kurzen Moment die Funktionsüberladung (die c ++ statisch macht) und den Mehrfachversand verwechselt. errare humanum est ...
miraculixx

Antworten:

12

Die Begriffe bedeuten Folgendes:

  • statischer Versand = Der Versandauftrag wird zur Kompilierungszeit definiert . Es bedeutet einfach, dass jeder Funktions- / Methodenaufruf immer dieselbe Funktion aufruft foo()oder x.foo()aufruft - dies wird einmal eingerichtet und bleibt dann so. Dies bedeutet, dass der Compiler den Typ xzur Kompilierungszeit bestimmen kann .

  • dynamischer Versand = Der Versandauftrag wird zur Laufzeit aufgelöst . Dies bedeutet, dass der Compiler eine Nachschlagetabelle aller Funktionen / Methoden erstellt und festlegt, welche zur Laufzeit tatsächlich aufgerufen werden soll. Angenommen, es gibt Klasse A und B, die beide die Schnittstelle X mit der Methode implementieren X.bar(). Wird zur Laufzeit ygeprüft und basiert entweder auf seiner tatsächlichen Klasse A.bar()oder B.bar()wird aufgerufen.

  • mehrfacher dynamischer Versand = Die Versandreihenfolge ist abhängig von Funktions- / Methodenname + Argumenttypen (= auch als Signatur bezeichnet ), und die tatsächliche Implementierung, die aufgerufen wird, wird zur Laufzeit dynamisch bestimmt . Angenommen, Klasse A implementiert Methoden A.fooBar(int)und A.fooBar(char *), und a.fooBar(x)in Ihrem Programm wird aufgerufen . Zur Laufzeit werden beide aund xgeprüft und die tatsächlich aufzurufende Methode anhand des Typs von bestimmt x.

Weitere Informationen zum dynamischen Versand und zum mehrfachen dynamischen Versand finden Sie in Wikipedia .

Miraculixx
quelle
1
Kann ich behandeln, dass C ++ -freie Funktionen statischen Mehrfachversand unterstützen ?
Eonil
Nun, per Definition bedeutet Nein - Mehrfachversand dynamisch. Mit c ++ freien Funktionen erledigt AFAIK der Compiler die ganze Arbeit, die wirklich statisch ist und immer den Funktionsnamen + die Signatur betrachtet.
Miraculixx
1
Wenn der Begriff Versand sowohl statisch als auch dynamisch verwendet werden kann, warum bedeutet Mehrfachversand dynamisch? Was ist mit statischem Mehrfachversand ?
Eonil
1
Statischer Versand bedeutet, dass der Compiler eine Nachschlagetabelle aller Funktionen einschließlich der Signatur erstellt. Jeder statische Versand ist effektiv ein Mehrfachversand. Wenn Sie also sagen, dass mehrere Versandmitarbeiter davon ausgehen, dass Sie dynamisch sind .
Miraculixx
@miraculixx Nicht jeder statische Versand ist Mehrfachversand. Dies ist in C ++ der Fall, aber im Allgemeinen nicht.
user253751
12

Mein Rat hier ist: Überdenken Sie diesen nicht. Versand bedeutet einfach senden. Versenden Sie ein Ereignis an einen Listener, senden Sie einen Interrupt an einen Handler, senden Sie eine Nachricht an einen Empfänger, senden Sie einen Aufruf an eine Prozedur oder Funktion: alle Aspekte desselben Grundkonzepts. Senden Sie die Daten an den Code, der sie verarbeitet. Auflösung bedeutet die Wahl zwischen verfügbaren Zielen und ist nur ein Teil des Versands.

In Bezug auf den Code beginnt der Versand mit einer Art Informationspaket und etwas, das angibt, wohin es gesendet werden soll, und endet, wenn das Paket gesendet (versendet) wurde. In allen Sprachen ist eine Art Versandmechanismus integriert, aber viele implementieren Auflösungs- und Versandschemata, um einem bestimmten Zweck gerecht zu werden. Interrupt-Behandlung und Windows-Nachrichtenverarbeitung sind Beispiele, die mir in den Sinn kommen.

C ++ kann eine statische oder dynamische Auflösung verwenden. Wenn jedoch Funktionen basierend auf Argumenttypen ausgewählt werden, kann dies nur zur Kompilierungszeit erfolgen. Smalltalk / Objective C und Ruby lösen Versendungen zur Laufzeit auf, ebenso wie viele dynamische Sprachen.

Einzelversand bedeutet, dass ein einzelnes Argument als Empfänger betrachtet wird und bestimmt, welche Methode aufgerufen wird. Die Methode befindet sich normalerweise in der Klasse für dieses Empfängerobjekt, und die Methodensignatur wird in einen Versatz in einer Versandtabelle (vtable) in dieser Klasse konvertiert. Das privilegierte Objekt in C ++ ist das vor dem Punkt, der zum 'this'-Zeiger wird.

Mehrfachversand bedeutet keinen privilegierten Empfänger, sondern normalerweise eine Mustervergleichsoperation über alle Argumenttypen hinweg. Das Common Lisp Object System verwendet diesen Ansatz. Siehe https://en.wikipedia.org/wiki/Multiple_dispatch .

In C ++ mit überladenen Operatoren müssen A + B und B + A an verschiedene Methoden gesendet werden. In CLOS können sie gleich sein.

Ich bevorzuge wahrscheinlich den Begriff MultiMethods, da es sich eher um eine Multi-Faktor-Auflösung als um einen Mehrfachversand an sich handelt. Siehe http://c2.com/cgi/wiki?MultiMethods . Auch http://www.codeproject.com/Articles/242749/Multiple-dispatch-and-double-dispatch .

david.pfx
quelle
1
"C ++ kann statische oder dynamische Auflösung verwenden ... dies kann nur zur Kompilierungszeit erfolgen", was ist mit virtuellen Methoden? Diese werden zur Laufzeit dynamisch ermittelt und hängen von der Methodensignatur ab
miraculixx
Hoffentlich macht meine Bearbeitung klarer, was ich beabsichtigt habe.
david.pfx
0

C ++ hat keinen mehrfachen (dynamischen) Versand. Folgendes berücksichtigen:

#include <iostream>

struct Foo {
   virtual ~Foo() {}
};

struct FooOne : public Foo {};

struct Bar {
   virtual ~Bar() {}
   virtual void dispatch (const Foo &) {
      std::cout << "Bar::Dispatch(const Foo &)\n";
   }
};

struct BarOne : public Bar {
   using Bar::dispatch;
   virtual void dispatch (const Foo &) {
      std::cout << "BarOne::Dispatch(const Foo &)\n";
   }
   virtual void dispatch (const FooOne &) {
      std::cout << "BarOne::Dispatch(const FooOne &)\n";
   }
};

void process (Bar & bar, const Foo & foo) {
   bar.dispatch (foo);
}

int main () {
   Foo foo;
   Bar bar;
   FooOne foo_one;
   BarOne bar_one;

   process (bar, foo);
   process (bar, foo_one);

   process (bar_one, foo);
   process (bar_one, foo_one);

   bar_one.dispatch (foo_one);

   return 0;
}

Die Ausgabe von oben ist

Bar::Dispatch(const Foo &)
Bar::Dispatch(const Foo &)
BarOne::Dispatch(const Foo &)
BarOne::Dispatch(const Foo &)
BarOne::Dispatch(const FooOne &)

Innerhalb von process(Foo& foo, const Bar& bar)C ++ wird fooin der Anweisung ein dynamischer Versand für Argumente verwendet foo.dispatch(bar). Die dritte und vierte Ausgabezeile zeigen diesen dynamischen Versand im C ++ - Stil in Aktion. Die vierte Ausgabezeile zeigt, dass C ++ keinen Mehrfachversand hat. Wenn dies der Fall wäre, wäre diese vierte Ausgabezeile dieselbe wie die letzte.

Diese letzte Zeile? Das ist statischer Versand. Der Compiler weiß zur Kompilierungszeit genau, welche Funktion aufgerufen werden muss. Dieser letzte Aufruf geht nicht durch die virtuelle Tabelle.

David Hammen
quelle
Das Beispiel ist gültig und nützlich, aber der Mehrfachversand, auch bekannt als Multimethoden, geht noch weiter. In einer Sprache, die an einen Empfänger einer einzelnen Klasse gesendet wird, können Sie nicht einmal das Beispiel schreiben, das in CLOS natürlich vorkommt.
david.pfx