Na ciência da computação, uma tabela de despacho é uma estrutura de dados que mapeia uma série de ações conhecidas para seus códigos correspondentes, os quais podem ser recuperados posteriormente. Essa estrutura é geralmente implementada usando um vetor associativo para mapear nomes de métodos para um ponteiro de função correspondente ou um vetor simples com ponteiros de função com índices conhecidos.
Usos comuns incluem a implementação de late binding e funções virtuais na programação orientada a objetos e a implementação de chamadas de sistema.
Nas linguagens de programação orientadas a objetos que suportam funções virtuais, o compilador criará automaticamente uma tabela de despacho para cada classe que mapeia nomes de métodos para seus códigos correspondentes. Essa tabela é chamada de tabela de método virtual, ou vtable, e um ponteiro para a tabela é armazenado em todos os objetos criados a partir dessa classe, chamado de ponteiro virtual ou vptr. Como um objeto sempre tem acesso direto aos seus métodos usando o vptr, métodos virtuais podem ser dinamicamente chamados em tempo de execução sem precisar saber a classe específica de que o objeto é construído. Essa camada de indireção faz com que polimorfismo e late binding sejam possíveis, o que é um aspecto fundamental da programação orientada a objetos.
No design de núcleos de sistemas operacionais, chamadas de sistema são geralmente implementadas usando uma tabela de despacho de índices mapeando para as ações de sistema privilegiadas correspondentes. Por exemplo, no Linux, a chamada de sistema sys_exit tem um índice de 60 e pode ser chamada passando 60 no registrador apropriado e chamando uma interrupção.
; Chama sys_exit com codigo de saida 0
mov rax, 60
mov rdi, 0
syscall
Como chamadas de sistema apenas requerem um número para referenciar a ação do kernel subjacente, elas podem ser chamadas pelo espaço de usuário quando, na verdade, estão chamando código no espaço do kernel. Isso melhora a segurança do sistema por assegurar que códigos privilegiados só podem ser executados pela interface estreita que cada chamada oferece.
O código a seguir mostra uma forma de implementar uma tabela de despacho em Perl, usando um vetor associativo para guardar referências de código (conhecidos também como ponteiros de função).
# Definir a tabela usando uma code-ref anonima e uma code-ref nomeada
my %dispatch = (
"-h" => sub { return "hello\n"; },
"-g" => \&say_goodbye
);
sub say_goodbye {
return "goodbye\n";
}
# Obter o code ref da tabela, e o chamar
my $sub = $dispatch{$ARGV[0]};
print $sub ? $sub->() : "unknown argument\n";
Executando este programa em Perl como perl greet -h vai produzir "hello", e executando-o como perl greet -g vai produzir "goodbye".
Uma tabela de despacho pode ser implementada em JavaScript usando um objeto para armazenar definições de função anônimas.
// Tabela de despacho de acoes e um fallback
const actions = {
action1() { console.log("action1 called"); },
action2() { console.log("action2 called"); },
action3() { console.log("action3 called"); },
fallback() { console.log("fallback called"); }
};
function performAction(key) {
const action = Object.hasOwn(actions, key) ? key : "fallback";
return actions[action]();
}
performAction("action1"); // mostra "action1 called"
performAction("action3"); // mostra "action3 called"
performAction("action5"); // mostra "fallback called"
Em Lua, tabelas podem armazenar qualquer valor, incluindo funções, fazendo com que implementar uma tabela de despacho simples seja trivial.
-- Tabela de despacho de acoes e um fallback
local actions = {
action1 = function ()
print('action1 called')
end,
action2 = function ()
print('action2 called')
end,
action3 = function ()
print('action3 called')
end,
fallback = function ()
print('fallback called')
end
}
function perform_action(key)
if actions[key] ~= nil then
return actions[key]()
end
return actions.fallback()
end
perform_action('action1') -- mostra "action1 called"
perform_action('action3') -- mostra "action3 called"
perform_action('action5') -- mostra "fallback called"