Domanda

Ho definito una "Azione" classe astratta pura in questo modo:

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

E rappresentato ogni comando l'utente può eseguire con una classe.

Per effettiva undo / redo mi piacerebbe fare qualcosa di simile:

Annulla

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

Ripristina

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

Il compilatore, ovviamente, non accetta questo, perché "Azione" è una classe astratta che non può essere istantiated.

Quindi, devo ridisegnare tutto o c'è una semplice soluzione a questo problema?

È stato utile?

Soluzione

È possibile memorizzare le azioni come i puntatori, che manterrà il compilatore felice.

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

C'è un altro motivo per cui std::vector<Action> historyStack; non funziona e questo è affettare. Quando si aggiungono oggetti di classi derivate al vettore saranno gettati alla classe di base e sciolto tutto il loro polimorfismo. Di più qui: Ciò che è oggetto affettare

Modifica considerare di usare ptr_vector per gestire il ciclo di vita degli oggetti nel vettore: http://www.boost.org/doc/libs/1_37_0/libs/ptr_container/doc/tutorial.html

Altri suggerimenti

spedizione polimorfico avviene solo tramite puntatori o riferimenti in C ++ in ogni caso. Potrebbe non essere in grado di creare un valore di azione, ma troverete che sarete in grado di creare riferimenti e puntatori a azioni.

pop deve semplicemente restituire un puntatore (possibilmente intelligente), o un riferimento, ad un'azione. Un approccio potrebbe essere quello di utilizzare std :: auto_ptr e spinta :: ptr_deque , tale volontà (con l'uso corretto) assicurare che le azioni siano adeguatamente puliti dopo.

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

Un'altra opzione potrebbe essere un std::stack di boost::shared_ptr<Action> o simili. Oppure si può semplicemente utilizzare i puntatori prime, ma è necessario fare attenzione che la proprietà è gestita correttamente.

È possibile memorizzare i puntatori alle operazioni eseguite nella coda.

Per esempio:

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

Quindi:

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

E

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

Ovviamente si deve usare nuovo e eliminare per creare e liberare memoria per effettivi Azione oggetti e non credo che si può usare auto_ptr con contenitori standard in modo da avere di gestire la memoria manualmente o implementare qualche altro metodo. Ma questo non dovrebbe essere un grosso problema se si avvolgono buffer di annullamento in una classe.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top