2011-03-05 9 views
6

Descripción breve:
Estoy iterando sobre un vector que llama a una función virtual en cada objeto del vector para ejecutar una secuencia de acciones. El vector es de la clase base como es el iterador. Todos los objetos son niños. Cuando se llama a la función virtual, ejecuta la función de la clase base.Funciones virtuales: iteración sobre un vector <Base Class> que se rellena con los objetos de la subclase

(Really) Long Descripción: Estoy intentando modelar una criatura que tiene un conjunto de comportamientos. Mi clase base abstracta es con sólo dos funciones (virtuales), que todas las subclases han anulado:

class Behavior 
{ 
public: 
    Behavior(); 
    ~Behavior(void){} 
virtual void execute(){} 
virtual BEHAVIOR_TYPE getType() {return m_Type;} 


protected: 
BEHAVIOR_TYPE m_Type; 
}; 

que han creado una serie de comportamientos de los niños, tales como movimiento, consumir, explorador, etc.

class Move : 
    public Behavior 
{ 
public: 
BEHAVIOR_TYPE getType() {return m_Type;} 
    enum Direction {N, NE, E, SE, S, SW, W, NW}; 
Move(DOCO * d); 
~Move(void); 
void execute() ; 
    Direction chooseDirection(); 
    void setDirection(Direction newDirection); 
private: 
    Direction m_Direction; 
    DOCO *I; 
BEHAVIOR_TYPE m_Type; 

}; 

I creó un vector sobre el que empujé instancias de cada subclase comportamiento, así como un iterador de atravesar que:

vector<Behavior> m_Behavior; 
vector<Behavior>::iterator bIt; 

Cuando la criatura obtiene una secuencia de acción, trato de iterat correo sobre el vector, eliminar la referencia al repetidor, y llamar a la función de ejecutar:

void World::justDoIt() 
{ 
    for(dIt=myDOCO.begin(); dIt!=myDOCO.end(); ++dIt) 
{ 
    vector<Behavior>::iterator myBehavior=(dIt)->getFirstBehavior(); 
    vector<Behavior>::iterator end=(dIt)->getLastBehavior(); 
    for(myBehavior; myBehavior!=end; ++myBehavior) 

     (*myBehavior).execute(); 
} 
} 

El problema es que se ejecuta la función de los padres en lugar de la función del niño.

En mi comprensión de la vinculación tardía debería llamar automáticamente a la función adecuada según el tipo de objeto que la llamaba en lugar del tipo de puntero con el que se llamaba, y en mi código anticipé que estaría apuntando a el objeto niño.

Obviamente he cometido un error y de alguna manera le dije al programa que quiero que estos sean tratados como padres en lugar de hijos, pero no puedo encontrar mi error.

Un segundo síntoma es que no me permitirá hacer que los padres funcionen puramente virtuales, porque dice que no puede instanciar una clase abstracta. No estoy ejemplificando explícitamente en ninguna parte de mi código, pero debe haber un lugar en el que lo esté haciendo implícitamente. No puedo encontrar dónde, sin embargo. Ciertamente, crear un vector para contener objetos de la clase padre no requiere la creación de instancias del padre, y esa es la única vez que hago referencia directamente a la clase padre.

Cualquier ayuda sería muy apreciada.

+0

Tiene que haber docenas de duplicados para poner _objects_ clase base (en lugar de _pointers_) en una Contenedor STL, aunque no puedo, cajero automático, encuentre uno. Uno de ellos debería convertirse probablemente en [entrada de preguntas frecuentes] (http://stackoverflow.com/questions/tagged/c%2b%2b-faq). – sbi

Respuesta

10

La clase vector<Behavior> hace copias de lo que sea que almacene dentro, utilizando el constructor de copia Behavior::Behavior(const Behavior&);. Esto destruye el polimorfismo. Es necesario utilizar un puntero o puntero inteligente en el contenedor en su lugar:

vector<Behavior*> m_Behavior; // I will take care of new and delete 
vector<shared_ptr<Behavior> > m_Behavior; // easier 

Si usted no tiene std::shared_ptr o std::tr1::shared_ptr en #include <memory> o similares, tal vez se puede usar Boost.

+0

¡Muchas gracias! ¡No sabía sobre punteros compartidos! – Sisyphus

+2

si tiene 'std :: shared_ptr', luego use' std :: unique_ptr' aquí. –

4

Agregas instancias de clases al vector. Esto resulta en slicing.

Lo que hay que hacer es añadir punteros a los casos de conductas y modificar el bucle de hacer

(*myBehavior)->execute(); 
+0

¡Muchas gracias! – Sisyphus

Cuestiones relacionadas