O que é despacho? Isso implica resolução dinâmica?

8

AFAIK, o termo despacho significa apenas uma resolução e chamada de método. Não importa se é estático ou dinâmico. Vi muitas pessoas usando um termo como despacho estático e despacho dinâmico .

O que me deixa confuso é que também existem algumas descrições misteriosas. Eu estava tentando entender o que é despacho múltiplo , e parece apenas selecionar um subprograma por tipos de parâmetros . Se eu entendi direito, pode haver tanto despacho múltiplo estático quanto despacho múltiplo dinâmico , e podemos dizer que o C ++ está fornecendo despacho múltiplo por meio de funções livres.

Mas, o artigo da Wikipedia sobre despacho múltiplo diz que o C ++ não tem despacho múltiplo porque não possui resolução dinâmica de função por vários parâmetros. E eu realmente não entendo diferença conceitual entre o exemplo Common Lisp e a função sobrecarregada de C ++. Porque não consigo encontrar nenhuma diferença conceitual, a menos que o termo despacho múltiplo implique despacho dinâmico . E percebi que estou confundindo o que realmente é o despacho

Também verifiquei a entrada do controle de qualidade Multiple Dispatch vs. Function Overloading , e parece que a resposta pressupõe que o termo despacho seja basicamente dinâmico . Isso também me deixa confuso.

Qual é o significado correto do termo despacho ? Isso implica resolução dinâmica ? Este termo é bem definido ou apenas convencional? o que estou perdendo?

Eonil
fonte
1
"Artigo da Wikipedia sobre despacho múltiplo indica que o C ++ não tem despacho múltiplo" - a qual artigo você está se referindo? C ++ tem vários despachos. E sim, múltiplos expedição faz implicam dinâmico (ver en.wikipedia.org/wiki/Multiple_dispatch )
miraculixx
@miraculixx Esse é o artigo. E o artigo da Wikipedia não menciona atributos estáticos / dinâmicos, então fiquei totalmente confuso.
Eonil
1
@miraculixx - C ++ não tem vários despachos. Você precisa falsificá-lo com algum padrão de design, como o Padrão do Visitante.
David Hammen
@ David, de fato, acho que fiquei confuso lá, e por um breve momento misturei sobrecarga de função (que c ++ faz estaticamente) e despacho múltiplo. errare humanum est ...
miraculixx

Respostas:

12

Os termos significam o seguinte:

  • expedição estática = a ordem de expedição é definida no momento da compilação . Significa simplesmente que qualquer chamada de função / método diz foo()ou x.foo()sempre invocará a mesma função - isso é estabelecido uma vez e permanece assim. Isso implica que o compilador pode determinar o tipo de xem tempo de compilação.

  • despacho dinâmico = a ordem de despacho é resolvida no tempo de execução . Isso significa que o compilador cria uma tabela de pesquisa de todas as funções / métodos e determina qual delas realmente chamar em tempo de execução. Digamos não há classe A e B, sendo que ambos X implementar a interface com o método X.bar(). Em tempo de execução, yé examinado e com base em sua classe real, A.bar()ou B.bar()é chamado.

  • despacho dinâmico múltiplo = a ordem de despacho depende da função / nome do método + tipos de argumento (= assinatura ), e a implementação real que é chamada é determinada dinamicamente no tempo de execução. Diga que a classe A implementa métodos A.fooBar(int)e A.fooBar(char *), e existe uma chamada a.fooBar(x)no seu programa. No tempo de execução ambos ae xsão examinadas e o método real de chamada é determinado com base no tipo de x.

Consulte a Wikipedia para obter mais informações sobre despacho dinâmico e despacho dinâmico múltiplo .

miraculixx
fonte
1
Posso tratar funções livres de C ++ suportando despacho múltiplo estático ?
Eonil
bem, por definição, não - despacho múltiplo implica dinâmico. Com funções livres de c ++, o AFAIK, o compilador, faz todo o trabalho que é realmente despachado estático, sempre olhando para o nome da função + assinatura.
22414 Miraculixx
1
Se o termo despacho pode ser usado em estático e dinâmico, por que o despacho múltiplo implica em dinâmico? E o envio múltiplo estático ?
Eonil
1
despacho estático significa que o compilador cria uma tabela de pesquisa de todas as funções, incluindo a assinatura. Qualquer despacho estático é efetivamente despacho múltiplo; portanto, por convenção, quando você diz que várias pessoas de despacho assumem que você implica em dinâmico .
21814
@miraculixx Nem todo envio estático é múltiplo. Esse é o caso em C ++, mas não em geral.
user253751
12

Meu conselho aqui é: não pense demais neste. Despachar significa simplesmente enviar. Despache um evento para um ouvinte, despache uma interrupção para um manipulador, despache uma mensagem para um destinatário, despache uma chamada para um procedimento ou função: todos os aspectos do mesmo conceito básico. Envie os dados para o código que os manipulará. Resolução significa escolher entre os destinos disponíveis e é apenas uma parte do envio.

Em termos de código, o despacho começa com algum tipo de pacote de informações e algo que indica para onde deve ser enviado, e termina quando o pacote é enviado (despachado). Todos os idiomas têm algum tipo de mecanismo de despacho incorporado, mas muitos implementam esquemas de resolução e despacho para atender a um propósito único. Manipulação de interrupção e processamento de mensagens do Windows são exemplos que vêm à mente.

O C ++ pode usar resolução estática ou dinâmica, mas se escolher entre funções com base em tipos de argumento, poderá fazê-lo apenas em tempo de compilação. Smalltalk / Objective C e Ruby resolvem despachos em tempo de execução, assim como muitas linguagens dinâmicas.

Despacho único significa que um único argumento é considerado o receptor e determina qual método é chamado. O método geralmente está na classe para esse objeto receptor e a assinatura do método é convertida em um deslocamento em uma tabela de expedição (vtable) nessa classe. O objeto privilegiado em C ++ é aquele antes do ponto, que se torna o ponteiro 'this'.

O envio múltiplo significa que não há receptor privilegiado, mas normalmente uma operação de correspondência de padrões em todos os tipos de argumentos. O Common Lisp Object System usa essa abordagem. Consulte https://en.wikipedia.org/wiki/Multiple_dispatch .

No C ++ com operadores sobrecarregados, A + B e B + A devem despachar para métodos diferentes. No CLOS, eles podem ser os mesmos.

Eu provavelmente prefiro o termo MultiMethods, já que é resolução multifatorial em vez de envio múltiplo em si. Consulte http://c2.com/cgi/wiki?MultiMethods . Também http://www.codeproject.com/Articles/242749/Multiple-dispatch-and-double-dispatch .

david.pfx
fonte
1
"O C ++ pode usar resolução estática ou dinâmica ... somente em tempo de compilação", e os métodos virtuais? Aqueles são determinados dinamicamente em tempo de execução e não dependem de assinatura do método
miraculixx
Espero que minha edição torne mais claro o que eu pretendia.
David.pfx
0

O C ++ não possui vários despachos (dinâmicos). Considere o seguinte:

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

A saída acima é

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

Dentro process(Foo& foo, const Bar& bar), o C ++ usa despacho dinâmico no argumento fooda instrução foo.dispatch(bar). A terceira e quarta linhas de saída mostram esse despacho dinâmico no estilo C ++ em ação. A quarta linha de saída demonstra que o C ++ não tem vários despachos. Nesse caso, a quarta linha de saída seria a mesma que a anterior.

Essa linha final? Isso é despacho estático. O compilador sabe em tempo de compilação exatamente qual função precisa ser chamada. Esta chamada final não passa pela tabela virtual.

David Hammen
fonte
O exemplo é válido e útil, mas o despacho múltiplo, também conhecido como multimétodo, vai além. Em um idioma enviado para um único receptor de classe, você não pode nem escrever o tipo de exemplo que vem naturalmente no CLOS.
David.pfx