2009-11-17 16 views
29

Estoy tratando de entender qué es el despacho múltiple. Leí muchos textos diferentes, pero aún no tengo idea de qué es el despacho múltiple y para qué sirve. Tal vez lo que me falta es una pieza de código que utiliza múltiples despachos. Por favor, ¿puedes escribir un pequeño fragmento de código en C++ usando el envío múltiple para que pueda ver que no se puede compilar/ejecutar correctamente porque C++ solo tiene un solo despacho? Necesito ver la diferencia. Gracias.Despacho múltiple en C++

+2

C++ no lo soporta directamente, pero estoy seguro de que de alguna manera puede emular esto. Nunca he usado MD o incluso vi un diseño agradable en otros idiomas que me hizo querer tener MD en C++. Los fanáticos de Dylan lo enumeran como una de las características del lenguaje de Dylan. Pero hasta donde sé, huele como un mal diseño porque la cantidad de funciones que deberías escribir crece exponencialmente. No me gustaría escribir tantas funciones. – sellibitze

+4

Has usado MD en cualquier momento que hayas usado el patrón 'Visitor'. –

+1

Un ejemplo simple usando C++ 11: http://ideone.com/lTsc7M – Jarod42

Respuesta

54

Multi-dispatch es la capacidad de elegir qué versión de una función llamar en función del tipo de tiempo de ejecución de los argumentos pasados ​​a la llamada a la función.

He aquí un ejemplo que no funciona la derecha en C++ (no probado):

class A { }; 
class B : public A { }; 
class C : public A { } 


class Foo 
{ 
    virtual void MyFn(A* arg1, A* arg2) { printf("A,A\n"); } 
    virtual void MyFn(B* arg1, B* arg2) { printf("B,B\n"); } 
    virtual void MyFn(C* arg1, B* arg2) { printf("C,B\n"); } 
    virtual void MyFn(B* arg1, C* arg2) { printf("B,C\n"); } 
    virtual void MyFn(C* arg1, C* arg2) { printf("C,C\n"); } 
}; 

void CallMyFn(A* arg1, A* arg2) 
{ 
    // ideally, with multi-dispatch, at this point the correct MyFn() 
    // would be called, based on the RUNTIME type of arg1 and arg2 
    pFoo->MyFn(arg1, arg2); 
} 

... 

A* arg1 = new B(); 
A* arg2 = new C(); 
// Using multi-dispatch this would print "B,C"... but because C++ only 
// uses single-dispatch it will print out "A,A" 
CallMyFn(arg1, arg2); 
+2

+1 para el código que indica claramente el problema – neuro

+1

Gracias, esta respuesta es más o menos lo que necesitaba ver.Ahora solo tengo que averiguar, ¿por qué demonios alguien necesita tal cosa? De todos modos, gracias por el buen ejemplo. – Martin

+3

una aplicación es física, un cubo colisionando con otro cubo es una intersección, un cubo colisionando con un avión es una intersección diferente. Por lo tanto, terminas con bastantes diferentes métodos de detección de colisiones, y el envío es bastante útil para eso. Aquí hay un hilo en el despacho doble, http://www.gamedev.net/topic/453624-double-dispatch-in-c/ – QuantumKarl

18

envío múltiple es cuando la función que se ejecuta depende del tipo de tiempo de ejecución de más de un objeto.

C++ tiene despacho único porque cuando se usan funciones virtuales, la función real que se ejecuta depende solo del tipo de tiempo de ejecución del objeto a la izquierda de -> o. operador.

Estoy luchando por pensar en un caso de programación real para despacho múltiple. Tal vez en un juego donde varios personajes luchan entre sí.

void Fight(Opponent& opponent1, Opponent& opponent2); 

El ganador de una pelea puede depender de las características de los dos oponentes, por lo que es posible que desee este llamado a despachar a uno de los siguientes, dependiendo de los tipos de tiempo de ejecución de ambos argumentos:

void Fight(Elephant& elephant, Mouse& mouse) 
{ 
    mouse.Scare(elephant); 
} 

void Fight(Ninja& ninja, Mouse& mouse) 
{ 
    ninja.KarateChop(mouse); 
} 

void Fight(Cat& cat, Mouse& mouse) 
{ 
    cat.Catch(mouse); 
} 

void Fight(Ninja& ninja, Elephant& elephant) 
{ 
    elephant.Trample(ninja); 
} 

// Etc. 

Lo que hace la función depende de los tipos de ambos argumentos, no solo uno. En C++, puede que tenga que escribir esto como algunas funciones virtuales. Se seleccionaría una función virtual según un argumento (este puntero). Entonces, la función virtual puede necesitar contener un interruptor o algo para hacer algo particular al otro argumento.

+2

+1 para los nombres ;-) – neuro

+4

Me faltan piratas. Pero está bien, gracias por ejemplo. – Martin

+3

Un ejemplo práctico que sucede a menudo es tratar diferentes subclases de forma diferente a una matriz de punteros de clase base. – kizzx2

3

En único despacho la función ejecutada depende solo del tipo de objeto. En despacho doble la función ejecutada depende del tipo de objeto y del parámetro .

En el siguiente ejemplo, la función Area() se invoca usando única expedición, y Intersect() basa en doble envío, ya que toma un parámetro Shape.

class Circle; 
class Rectangle; 
class Shape 
{ 
    virtual double Area() = 0; // Single dispatch 

    // ... 
    virtual double Intersect(const Shape& s) = 0; // double dispatch, take a Shape argument 
    virtual double Intersect(const Circle& s) = 0; 
    virtual double Intersect(const Rectangle& s) = 0; 
}; 

struct Circle : public Shape 
{ 
    virtual double Area() { return /* pi*r*r */; } 

    virtual double Intersect(const Shape& s); 
    { return s.Intersect(*this) ; } 
    virtual double Intersect(const Circle& s); 
    { /*circle-circle*/ } 
    virtual double Intersect(const Rectangle& s); 
    { /*circle-rectangle*/ } 
}; 

El ejemplo se basa en este article.

+0

+1 enlace de interés – neuro

+0

Hay una gran cantidad de espacios que tienes allí. – strager

+1

@strager 2 espacios adicionales :) Sería bueno si Stack Overflow pudiese formatear la cantidad de espacios que el espectador prefiere. – pilkch

11

ver este artículo escrito por B. BS: Open Multi-Methods for C++

+1

aunque di un +1, se suponía que debías poner un resumen para ese artículo ... También el artículo cubre solo el reemplazo del método, no todos los casos de envío múltiple. –