9

Tengo una pregunta sobre el despacho doble de C++. En el siguiente código, quiero que los resultados del segundo conjunto coincidan con los resultados del primer conjunto.Despacho doble/multimétodos en C++

No sé el tipo real (a menos que intente dynamic_cast) pero sé que el objeto se hereda del tipo BaseClass. ¿Cuál es la forma más eficiente (rendimiento-sabio) de lograr esto?

Después de buscar en Google por un tiempo me enteré del despacho doble y de los multimétodos loki. El problema que tengo con los ejemplos de Shape es que en mi aplicación, Processor y BaseClass son completamente independientes y no tienen un método común que puedan llamar el uno al otro. En segundo lugar, solo hay un procesador (es decir, nada hereda de él).

Gracias por cualquier ayuda.

#include <iostream> 
#include <string> 
using namespace std; 

class BaseClass{ 
public: 
     BaseClass(){} 
     virtual void myFunction(){cout << "base myFunction called" << endl;} 
}; 

class Derived1: public BaseClass{ 
public: 
     Derived1():BaseClass(){} 
     void myFunction(){cout << "Derived1 myFunction called" << endl;} 
}; 


class Derived2: public BaseClass{ 
public: 
     Derived2():BaseClass(){} 
     void myFunction(){cout << "Derived2 myFunction called" << endl;} 
}; 

class Derived3: public BaseClass{ 
public: 
     Derived3():BaseClass(){} 
     void myFunction(){cout << "Derived3 myFunction called" << endl;} 

}; 

class Processor{ 
public: 
     Processor(){} 
     virtual void processObj(BaseClass* bc){cout << "got a base object" << endl; bc->myFunction();} 
     virtual void processObj(Derived1* d1){cout << "got a derived1 object" << endl; d1->myFunction();} 
     virtual void processObj(Derived2* d2){cout << "got a derived2 object" << endl; d2->myFunction(); } 
}; 


int main() { 
    BaseClass *bcp=new BaseClass(); 
    Derived1 *dc1p=new Derived1(); 
    Derived2 *dc2p=new Derived2(); 
    Derived3 *dc3p=new Derived3(); 

    Processor p;//can also use Processor* p = new Processor() 

    //first set results 
    p.processObj(bcp); 
    p.processObj(dc1p); 
    p.processObj(dc2p); 
    p.processObj(dc3p); 

    BaseClass *bcp1=bcp; 
    BaseClass *dc1p1=dc1p; 
    BaseClass *dc2p1=dc2p; 
    BaseClass *dc3p1=dc3p; 

    //second set results 
    p.processObj(bcp1); 
    p.processObj(dc1p1); 
    p.processObj(dc2p1); 
    p.processObj(dc3p1); 

    return 0; 
} 
+0

... editado para hacer que el código aparezca en un bloque de código –

Respuesta

4

Deberá poner un método virtual en BaseClass para llamar a processObj desde las clases derivadas.

class BaseClass{ 
public: 
     BaseClass(){} 
     virtual void ProcessThis(Processor &p) { p.processObj(this); } 
     virtual void myFunction(){cout << "base myFunction called" << endl;} 
}; 

class Derived1: public BaseClass{ 
public: 
     Derived1():BaseClass(){} 
     void ProcessThis(Processor &p) { p.processObj(this); } 
     void myFunction(){cout << "Derived1 myFunction called" << endl;} 
}; 

class Derived2: public BaseClass{ 
public: 
     Derived2():BaseClass(){} 
     void ProcessThis(Processor &p) { p.processObj(this); } 
     void myFunction(){cout << "Derived2 myFunction called" << endl;} 
}; 

class Derived3: public BaseClass{ 
public: 
     Derived3():BaseClass(){} 
     void ProcessThis(Processor &p) { p.processObj(this); } 
     void myFunction(){cout << "Derived3 myFunction called" << endl;} 

}; 

class Processor{ 
public: 
     Processor(){} 
     virtual void processObj(BaseClass* bc){cout << "got a base object" << endl; bc->myFunction();} 
     virtual void processObj(Derived1* d1){cout << "got a derived1 object" << endl; d1->myFunction();} 
     virtual void processObj(Derived2* d2){cout << "got a derived2 object" << endl; d2->myFunction(); } 
}; 

int main() { 
    BaseClass *bcp=new BaseClass(); 
    Derived1 *dc1p=new Derived1(); 
    Derived2 *dc2p=new Derived2(); 
    Derived3 *dc3p=new Derived3(); 

    Processor p;//can also use Processor* p = new Processor() 

    //first set results 
    bcp->ProcessThis(p); 
    dc1p->ProcessThis(p); 
    dc1p->ProcessThis(p); 
    dc3p->ProcessThis(p); 

    BaseClass *bcp1=bcp; 
    BaseClass *dc1p1=dc1p; 
    BaseClass *dc2p1=dc2p; 
    BaseClass *dc3p1=dc3p; 

    //second set results 
    bcp1->ProcessThis(p); 
    dc1p1->ProcessThis(p); 
    dc2p1->ProcessThis(p); 
    dc3p1->ProcessThis(p); 

    Processor p2; 
    bcp1->ProcessThis(p2); 
    dc1p1->ProcessThis(p2); 
    dc2p1->ProcessThis(p2); 
    dc3p1->ProcessThis(p2); 

    return 0; 
} 

Básicamente, desea el patrón Visitor, pero con un solo tipo de visitante. Puede ahorrarse un esfuerzo futuro y convertir Processor en una clase abstracta e implementar la única clase concreta ProcessorImpl, haciendo que sea trivial agregar otra clase de procesador en el futuro, o podría esperar hasta que surja esa situación y dejar las cosas como están por ahora. .

10

Te perdiste la parte "doble" del despacho doble.

El objetivo de este patrón es asegurarse de que se llama al método correcto del procesador: el método que acepta el tipo correcto. Dado que el procesador inicialmente no tiene conocimiento del tipo de objeto que se le ha pasado, necesita , el objeto para indicarle al procesador cuál es su tipo.

En esencia, cada objeto necesita un método virtual processMe(Processor &p), y el procesador lo llama. La implementación de processMe llama al p.processObject(this). ¡Pero esta vez, "esto" tiene un tipo conocido! Por lo tanto, en lugar de recurrencia infinita, termina con el derecho proceessObject llamado

0

Muchas gracias. ¡Esto resolvió mi problema y entiendo lo que significa el doble despacho! Aquí está el código completo para la posteridad (alguien por favor enséñeme cómo obtener el formato correcto):

#include <iostream> 
using namespace std; 

class BaseClass; 
class Derived1; 
class Derived2; 
class Derived3; 

class Processor { 
public: 
     Processor(){} 
     virtual void processObj(BaseClass* bc); 
     virtual void processObj(Derived1* d1); 
     virtual void processObj(Derived2* d2); 
}; 


class BaseClass{ 
public: 
     BaseClass(){} 
     virtual void ProcessThis(Processor &p) { p.processObj(this); } 
     virtual void myFunction(){cout << "base myFunction called" << endl;} 
}; 

class Derived1: public BaseClass{ 
public: 
     Derived1():BaseClass(){} 
     void ProcessThis(Processor &p) { p.processObj(this); } 
     void myFunction(){cout << "Derived1 myFunction called" << endl;} 
}; 

class Derived2: public BaseClass{ 
public: 
     Derived2():BaseClass(){} 
     void ProcessThis(Processor &p) { p.processObj(this); } 
     void myFunction(){cout << "Derived2 myFunction called" << endl;} 
}; 

class Derived3: public BaseClass{ 
public: 
     Derived3():BaseClass(){} 
     void ProcessThis(Processor &p) { p.processObj(this); } 
     void myFunction(){cout << "Derived3 myFunction called" << endl;} 

}; 

void Processor::processObj(BaseClass* bc){cout << "got a base object" << endl; bc->myFunction();} 
void Processor::processObj(Derived1* d1){cout << "got a derived1 object" << endl; d1->myFunction();} 
void Processor::processObj(Derived2* d2){cout << "got a derived2 object" << endl; d2->myFunction(); } 


int main() { 
    BaseClass *bcp=new BaseClass(); 
    Derived1 *dc1p=new Derived1(); 
    Derived2 *dc2p=new Derived2(); 
    Derived3 *dc3p=new Derived3(); 

    Processor p;//can also use Processor* p = new Processor() 

    //first set results 

    bcp->ProcessThis(p); 
    dc1p->ProcessThis(p); 
    dc2p->ProcessThis(p); 
    dc3p->ProcessThis(p); 

    BaseClass *bcp1=bcp; 
    BaseClass *dc1p1=dc1p; 
    BaseClass *dc2p1=dc2p; 
    BaseClass *dc3p1=dc3p; 

    //second set results 

    bcp1->ProcessThis(p); 
    dc1p1->ProcessThis(p); 
    dc2p1->ProcessThis(p); 
    dc3p1->ProcessThis(p); 

    Processor p2; 
    bcp1->ProcessThis(p2); 
    dc1p1->ProcessThis(p2); 
    dc2p1->ProcessThis(p2); 
    dc3p1->ProcessThis(p2); 

    return 0; 
} 
Cuestiones relacionadas