Pregunta

he definido una "acción" clase abstracta pura como esto:

class Action {
 public:
    virtual void execute () = 0;
    virtual void revert () = 0;
    virtual ~Action () = 0;
};

Y representado cada comando el usuario puede ejecutar con una clase.

Para real de deshacer / rehacer me gustaría hacer algo como esto:

Deshacer

Action a = historyStack.pop();
a.revert();
undoneStack.push(a);

Rehacer

Action a = undoneStack.pop();
a.execute();
historyStack.push(a);

El compilador, obviamente, no se hace esto, porque "acción" es una clase abstracta que no puede ser istantiated.

Por lo tanto, tengo que rediseñar todo o hay una solución simple a este problema?

¿Fue útil?

Solución

Debe almacenar acciones como punteros, que mantendrá el compilador feliz.

std::vector<Action*> historyStack;
/*...*/
historyStack.push_back(new EditAction(/*...*/));
Action* a = historyStack.pop();
a->revert();
undoneStack.push(a);

No es otra razón por la std::vector<Action> historyStack; no va a funcionar y eso es rebanar. Cuando la adición de objetos de clases derivadas al vector serán arrojados a la clase base y suelta todo su polimorfismo. Más acerca de ello aquí: Lo que es objeto de rebanado

editar Mira en el uso de ptr_vector para gestionar el tiempo de vida de los objetos en el vector: http://www.boost.org/doc/libs/1_37_0/libs/ptr_container/doc/tutorial.html

Otros consejos

despacho polimórfica sólo ocurre a través de punteros o referencias en C ++ de todos modos. Puede no ser capaz de crear un valor de acción, pero usted encontrará que usted será capaz de crear referencias y enlaces a acciones.

pop sólo tiene que devolver un puntero (posiblemente inteligente), o una referencia, a una acción. Un enfoque podría ser el uso de std :: auto_ptr y impulso :: ptr_deque , esta voluntad (con el uso correcto) garantizar que las acciones se limpian adecuadamente después.

std::auto_ptr<Action> a = historyStack.pop_front();
a->revert();
undoneStack.push_front(a);

Otra opción podría ser un std::stack de boost::shared_ptr<Action> o similar. O simplemente puede utilizar punteros primas, pero hay que tener cuidado de que la propiedad es administrada correctamente.

Debe almacenar punteros a las operaciones realizadas en la cola.

Por ejemplo:

std::vector<Action*> historyStack;
std::vector<Action*> undoneStack;

A continuación:

Action* a = historyStack.pop_back(); 
a->revert(); 
undoneStack.push_back( a ); 

Y:

Action* a = undoneStack.pop_back(); 
a->execute(); 
historyStack.push_back(a); 

Por supuesto que puedes usar nueva y eliminar para crear y la memoria libre para reales Acción objetos y yo no creo que se puede utilizar auto_ptr con contenedores estándar por lo que tiene que manejar su memoria de forma manual o implementar algún otro método. Pero esto no debería ser un gran problema si usted envuelve memoria intermedia de anulación en una clase.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top