Che cos'è la spedizione? Implica risoluzione dinamica?

7

AFAIK, il termine dispatch significa solo una risoluzione del metodo e una chiamata. Non importa se è statico o dinamico. Ho visto che molte persone usano un termine come invio statico e invio dinamico .

Ciò che mi rende confuso è che ci sono anche delle descrizioni misteriose. Stavo cercando di capire cosa è dispatch multiplo , e sembra selezionare un sottoprogramma per tipi di parametri . Se ho capito bene, possono esserci entrambi dispatch multipli statici e dispatch multipli dinamici , e possiamo dire che C ++ sta fornendo dispatch multipli via funzioni gratuite.

Tuttavia, l'articolo di Wikipedia su dispatch multipli dice che C ++ non ha dispatch multipli perché non ha una risoluzione dinamica della funzione in base a più parametri. E davvero non ottengo una differenza concettuale tra l'esempio di Common Lisp e la funzione di overload di C ++. Perché non riesco a trovare alcuna differenza concettuale a meno che il termine dispatch multipli implichi invio dinamico . E ho capito che sto confondendo ciò che dispatching è veramente

Ho anche controllato la voce QA Sovraccarico di più dispatch e funzioni , e sembra che la risposta sia prematura, il termine invio è fondamentalmente dinamico . Questo mi rende anche confuso.

Qual è il significato corretto del termine invio ? Comprende risoluzione dinamica ? Questo termine è ben definito o semplicemente convenzionale? Cosa mi manca?

    
posta Eonil 19.01.2014 - 07:25
fonte

3 risposte

9

I termini indicano quanto segue:

  • static dispatch = l'ordine di spedizione è definito in tempo di compilazione . Significa semplicemente che qualsiasi chiamata di funzione / metodo dice foo() o x.foo() invocherà sempre la stessa funzione - questa viene stabilita una volta e poi rimane tale. Ciò implica che il compilatore può determinare il tipo di x al momento della compilazione.

  • dynamic dispatch = l'ordine di spedizione è risolto in tempo di esecuzione . Ciò significa che il compilatore crea una tabella di ricerca di tutte le funzioni / metodi e determina quale chiamare effettivamente in fase di esecuzione. Diciamo che ci sono le classi A e B, che implementano entrambe l'interfaccia X con il metodo X.bar() . Al momento dell'esecuzione, viene esaminato y e in base alla sua classe effettiva viene chiamato A.bar() o B.bar() .

  • più dispatch dinamico = l'ordine di spedizione dipende dalla funzione / nome del metodo + tipi di argomenti (= aka firma ) e l'implementazione effettiva che viene chiamata è determinata dinamicamente in fase di runtime. Supponi che la classe A implementa i metodi A.fooBar(int) e A.fooBar(char *) , e nel tuo programma c'è una chiamata a a.fooBar(x) . Al momento dell'esecuzione vengono esaminati sia a che x e il metodo effettivo da chiamare viene determinato in base al tipo di x .

Vedi Wikipedia per ulteriori informazioni su invio dinamico e invio dinamico .

    
risposta data 19.01.2014 - 09:30
fonte
10

Il mio consiglio qui è: non pensarci troppo. Spedizione significa semplicemente inviare. Invia un evento a un ascoltatore, invia un interrupt a un gestore, invia un messaggio a un destinatario, invia una chiamata a una procedura o funzione: tutti gli aspetti dello stesso concetto di base. Invia i dati al codice che lo gestirà. Risoluzione significa scegliere tra le destinazioni disponibili ed è solo una parte della spedizione.

In termini di codice, la spedizione inizia con una sorta di pacchetto di informazioni e qualcosa che indica dove dovrebbe essere inviato, e finisce quando il pacchetto è stato inviato (inviato). Tutte le lingue hanno una sorta di meccanismo di invio integrato, ma molti implementano schemi di risoluzione e dispacciamento per soddisfare uno scopo unico. La gestione degli interrupt e l'elaborazione dei messaggi di Windows sono esempi che vengono in mente.

C ++ può usare la risoluzione statica o dinamica, ma se sceglie tra funzioni basate su tipi di argomenti, può farlo solo in fase di compilazione. Smalltalk / Objective C e Ruby risolvono i dispacci in fase di runtime, come fanno molti linguaggi dinamici.

Dispatch singolo significa che un singolo argomento è pensato come ricevitore e determina quale metodo viene chiamato. Il metodo è in genere nella classe per quell'oggetto destinatario e la firma del metodo viene convertita in un offset in una tabella di distribuzione (vtable) in tale classe. L'oggetto privilegiato in C ++ è quello precedente al punto, che diventa il puntatore "this".

Dispatch multipli significa nessun ricevitore privilegiato ma tipicamente un'operazione di abbinamento di modelli su tutti i tipi di argomenti. Il Common Lisp Object System utilizza questo approccio. Vedi link .

In C ++ con operatori sovraccaricati, A + B e B + A devono essere inviati a metodi diversi. In CLOS possono essere uguali.

Probabilmente preferisco il termine MultiMethods, dal momento che si tratta di una risoluzione a più fattori piuttosto che di un invio multiplo di per sé. Vedi link . Anche link .

    
risposta data 19.01.2014 - 08:17
fonte
0

C ++ non ha più (dinamico) dispatch. Considera quanto segue:

#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;
}

L'output di cui sopra è

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

All'interno di process(Foo& foo, const Bar& bar) , C ++ utilizza l'invio dinamico sull'argomento foo nell'istruzione foo.dispatch(bar) . La terza e la quarta riga di output mostrano questo dispatch dinamico in stile C ++ in azione. La quarta riga di output dimostra che C ++ non ha dispatch multipli. Se lo facesse, quella quarta linea di output sarebbe la stessa dell'ultima.

Quella linea finale? Questa è la spedizione statica. Il compilatore sa esattamente al momento della compilazione quale funzione deve essere chiamata. Questa chiamata finale non passa attraverso la tabella virtuale.

    
risposta data 19.01.2014 - 13:53
fonte

Leggi altre domande sui tag