I want to make an app where a user can edit a diagram (for example), which would provide the standard mechanisms of: Save, Load, Undo, and Redo.
A simple way to do it is to have classes for the diagram and for the various shapes in it, which implement serialization via save and load methods, and where all methods to edit them return UndoableActions that can be added to an UndoManager which calls their perform method and adds them to an undo stack.
The problem with the simple way described above is that it requires a lot of error-prone boilerplate work.
I know that the serialization (save/load) part of the work can be solved by using something like Google's Protocol Buffers or Apache Thrift, which generates the boiler-plate serialization code for you, but it doesn't solve the undo+redo problem. I know that for Objective C and Swift, Apple provides Core Data which does solve serialization + undo, but I'm not familiar with anything similar for C++.
Is there a good way non-error-prone to solve save+load+undo+redo with little boilerplate?
The problem with the simple way described above is that it requires a lot of error-prone boilerplate work.
I am not convinced that this is the case. Your approach sounds reasonable and using Modern C++ features and abstractions you can implement a safe and elegant interface for it.
For starters, you could use std::variant as a sum type for "undoable actions" - this will give you a type-safe tagged union for every action. (Consider using boost::variant or other implementations that can be easily found on Google if you do not have access to C++17). Example:
namespace action
{
// User dragged the shape to a separate position.
struct move_shape
{
shape_id _id;
offset _offset;
};
// User changed the color of a shape.
struct change_shape_color
{
shape_id _id;
color _previous;
color _new;
};
// ...more actions...
}
using undoable_action = std::variant<
action::move_shape,
action::change_shape_color,
// ...
>;
Now that you have a sum type for all your possible "undoable actions", you can define undo behavior by using pattern matching. I wrote two articles on variant "pattern matching" by overloading lambdas that you could find interesting:
"visiting variants using lambdas - part 1"
"visiting variants using lambdas - part 2"
Here's an example of how your undo function could look like:
void undo()
{
auto action = undo_stack.pop_and_get();
match(action, [&shapes](const move_shape& y)
{
// Revert shape movement.
shapes[y._id].move(-y._offset);
},
[&shapes](const change_shape_color& y)
{
// Revert shape color change.
shapes[y._id].set_color(y._previous);
},
[](auto)
{
// Produce a compile-time error.
struct undo_not_implemented;
undo_not_implemented{};
});
}
If every branch of match gets large, it could be moved to its own function for readability. Trying to instantiate undo_not_implemented or using a dependent static_assert is also a good idea: a compile-time error will be produced if you forget to implement behavior for a specific "undoable action".
That's pretty much it! If you want to save the undo_stack so that the history of actions is preserved in saved documents, you can implement a auto serialize(const undoable_action&) that, again, uses pattern matching to serialize the various actions. You could then implement a deserialize function that repopulates the undo_stack on file load.
If you find implementing serialization/deserialization for every action too tedious, consider using BOOST_HANA_DEFINE_STRUCT or similar solutions to automatically generate serialization/deserialization code.
Since you're concerned about battery and performance, I would also like to mention that using std::variant or similar tagged union constructs is on average faster and more lightweight compared to polymorphic hierarchies, as heap allocation is not required and as there is no run-time virtual dispatch.
About redo functionality: you could have a redo_stack and implement an auto invert(const undoable_action&) function that inverts the behavior of an action. Example:
void undo()
{
auto action = undo_stack.pop_and_get();
match(action, [&](const move_shape& y)
{
// Revert shape movement.
shapes[y._id].move(-y._offset);
redo_stack.push(invert(y));
},
// ...
auto invert(const undoable_action& x)
{
return match(x, [&](move_shape y)
{
y._offset *= -1;
return y;
},
// ...
If you follow this pattern, you can implement redo in terms of undo! Simply call undo by popping from the redo_stack instead of the undo_stack: since you "inverted" the actions it will perform the desired operation.
EDIT: here's a minimal wandbox example that implements a match function that takes in a variant and returns a variant.
The example uses boost::hana::overload to generate the visitor.
The visitor is wrapped in a lambda f that unifies the return type to the type of the variant: this is necessary as std::visit requires that the visitor always returns the same type.
If returning a type which is different from the variant is desirable, std::common_type_t could be used, otherwise the user could explicitly specify it as the first template parameter of match.
Two reasonable approaches to this problem are implemented in the frameworks Flip and ODB.
Code-generation / ODB
With ODB you need to add #pragma declarations to your code, and have it's tool generate methods that you use for save/load and for editing the model, like so:
#pragma db object
class person
{
public:
void setName (string);
string getName();
...
private:
friend class odb::access;
person () {}
#pragma db id
string email_;
string name_;
};
Where the accessors declared in the class are auto-generated by ODB so that all changes to the model can get captured and undo-transactions may be made for them.
Reflection with minimal boilerplate / Flip
Unlike ODB, Flip doesn't generate C++ code for you, but rather it requires your program to call Model::declare to re-declare your structures like so:
class Song : public flip::Object
{
public:
static void declare ();
flip::Float tempo;
flip::Array <Track> tracks;
};
void Song::declare ()
{
Model::declare <Song> ()
.name ("acme.product.Song")
.member <flip::Float, &Song::tempo> ("tempo");
.member <flip::Array <Track>, &Song::tracks> ("tracks");
}
int main()
{
Song::declare();
...
}
With the structured declared like so, flip::Object's constructor can initialize all the fields so that they can point to the undo stack, and all the edits on them are recorded. It also has a list of all the members so that flip::Object can implement the serialization for you.
The problem with the simple way described above is that it requires a lot of error-prone boilerplate work.
I would say that the actual problem is that your undo/redo logic is part of a component, that should ship only a bunch of data as a position, a content and so on.
A common OOP way to decouple the undo/redo logic from the data is the command design pattern.
The basic idea is that all the user interactions are converted to commands and those commands are executed on the diagram itself. They contain all the information required to perform an operation and to rollback it, as long as you maintain a sorted list of commands and undo/redo them in order (that is usually the user expectation).
Another common OOP pattern that can help you either to design a custom serialization utility or to use the most common ones is the visitor design pattern.
Here the basic idea is that your diagram should not care about the kind of components it contains. Whenever you want to serialize it, you provide a serializer and the components promote themselves to the right type when queried (see double dispatching for further details on this technique).
That being said, a minimal example is worth more than a thousand words:
#include <memory>
#include <stack>
#include <vector>
#include <utility>
#include <iostream>
#include <algorithm>
#include <string>
struct Serializer;
struct Part {
virtual void accept(Serializer &) = 0;
virtual void draw() = 0;
};
struct Node: Part {
void accept(Serializer &serializer) override;
void draw() override;
std::string label;
unsigned int x;
unsigned int y;
};
struct Link: Part {
void accept(Serializer &serializer) override;
void draw() override;
std::weak_ptr<Node> from;
std::weak_ptr<Node> to;
};
struct Serializer {
void visit(Node &node) {
std::cout << "serializing node " << node.label << " - x: " << node.x << ", y: " << node.y << std::endl;
}
void visit(Link &link) {
auto pfrom = link.from.lock();
auto pto = link.to.lock();
std::cout << "serializing link between " << (pfrom ? pfrom->label : "-none-") << " and " << (pto ? pto->label : "-none-") << std::endl;
}
};
void Node::accept(Serializer &serializer) {
serializer.visit(*this);
}
void Node::draw() {
std::cout << "drawing node " << label << " - x: " << x << ", y: " << y << std::endl;
}
void Link::accept(Serializer &serializer) {
serializer.visit(*this);
}
void Link::draw() {
auto pfrom = from.lock();
auto pto = to.lock();
std::cout << "drawing link between " << (pfrom ? pfrom->label : "-none-") << " and " << (pto ? pto->label : "-none-") << std::endl;
}
struct TreeDiagram;
struct Command {
virtual void execute(TreeDiagram &) = 0;
virtual void undo(TreeDiagram &) = 0;
};
struct TreeDiagram {
std::vector<std::shared_ptr<Part>> parts;
std::stack<std::unique_ptr<Command>> commands;
void execute(std::unique_ptr<Command> command) {
command->execute(*this);
commands.push(std::move(command));
}
void undo() {
if(!commands.empty()) {
commands.top()->undo(*this);
commands.pop();
}
}
void draw() {
std::cout << "draw..." << std::endl;
for(auto &part: parts) {
part->draw();
}
}
void serialize(Serializer &serializer) {
std::cout << "serialize..." << std::endl;
for(auto &part: parts) {
part->accept(serializer);
}
}
};
struct AddNode: Command {
AddNode(std::string label, unsigned int x, unsigned int y):
label{label}, x{x}, y{y}, node{std::make_shared<Node>()}
{
node->label = label;
node->x = x;
node->y = y;
}
void execute(TreeDiagram &diagram) override {
diagram.parts.push_back(node);
}
void undo(TreeDiagram &diagram) override {
auto &parts = diagram.parts;
parts.erase(std::remove(parts.begin(), parts.end(), node), parts.end());
}
std::string label;
unsigned int x;
unsigned int y;
std::shared_ptr<Node> node;
};
struct AddLink: Command {
AddLink(std::shared_ptr<Node> from, std::shared_ptr<Node> to):
link{std::make_shared<Link>()}
{
link->from = from;
link->to = to;
}
void execute(TreeDiagram &diagram) override {
diagram.parts.push_back(link);
}
void undo(TreeDiagram &diagram) override {
auto &parts = diagram.parts;
parts.erase(std::remove(parts.begin(), parts.end(), link), parts.end());
}
std::shared_ptr<Link> link;
};
struct MoveNode: Command {
MoveNode(unsigned int x, unsigned int y, std::shared_ptr<Node> node):
px{node->x}, py{node->y}, x{x}, y{y}, node{node}
{}
void execute(TreeDiagram &) override {
node->x = x;
node->y = y;
}
void undo(TreeDiagram &) override {
node->x = px;
node->y = py;
}
unsigned int px;
unsigned int py;
unsigned int x;
unsigned int y;
std::shared_ptr<Node> node;
};
int main() {
TreeDiagram diagram;
Serializer serializer;
auto addNode1 = std::make_unique<AddNode>("foo", 0, 0);
auto addNode2 = std::make_unique<AddNode>("bar", 100, 50);
auto moveNode2 = std::make_unique<MoveNode>(10, 10, addNode2->node);
auto addLink = std::make_unique<AddLink>(addNode1->node, addNode2->node);
diagram.serialize(serializer);
diagram.execute(std::move(addNode1));
diagram.execute(std::move(addNode2));
diagram.execute(std::move(addLink));
diagram.serialize(serializer);
diagram.execute(std::move(moveNode2));
diagram.draw();
diagram.undo();
diagram.undo();
diagram.serialize(serializer);
}
I've not implemented the redo action and the code is far from being a production-ready piece of software, but it acts quite well as a starting point from which to create something more complex.
As you can see, the goal is to create a tree diagram that contains both nodes an links. A component contains a bunch of data and knows how to draw itself. Moreover, as anticipated, a component accepts a serializer in case you want to write it down on a file or whatever.
All the logic is contained in the so called commands. In the example there are three commands: add node, add link and move node. Neither the diagram nor the components know anything about what's going on under the hood. All what the diagram knows is that it's executing a set of commands and those commands can be executed back a step at the time.
A more complex undo/redo system can contain a circular buffer of commands and a few indexes that indicate the one to substitute with the next one, the one valid when going forth and the one valid when going back.
It's quite easy to implement indeed.
This approach will help you decoupling the logic from the data and it's quite common when dealing with user interfaces.
To be honest, it's not something that came up suddenly to my mind. I found something similar while looking at how open-source software solved the issue and I've used it a few years ago in a software of mine. The resulting code is really easy to maintain.
Another approach you might want to consider is working with inmutable data structures and objects. Then, the undo/redo stack can be implemented as a stack of versions of the scene/diagram/document. Undo() replaces the current version with an older version from the stack, and so on. Because all data is inmutable, you can keep references instead of copies, so it is fast and (relatively) cheap.
Pros:
simple undo/redo
multithread-friendly
clean separation of "structure" and transient state (e.g. current selection)
may simplify serialization
caching/memoization/precomputation-friendly (e.g. bounding-box, gpu buffers)
Cons:
consumes a bit more memory
forces separation of "structure" and transient state
probably more difficult: for example, for a typical tree-like scenegraph, to change a node you would also need to change all the nodes along the path to the root; the old and new versions can share the rest of the nodes
Assuming that you're calling save() on a temporary file for each edit of the diagram (even if user doesn't explicitly call the save action) and that you undo only the latest action, you can do as follows:
LastDiagram load(const std::string &path)
{
/* Check for valid path (e.g. boost::filesystem here) */
if(!found)
{
throw std::runtime_exception{"No diagram found"};
}
//read LastDiagram
return LastDiagram;
}
LastDiagram undoLastAction()
{
return loadLastDiagram("/tmp/tmp_diagram_file");
}
and in your main app you handle the exception if thrown. In case you want to allow more undos, then you should think to a solution like sqlite or a tmp file with more entries.
If performance in time and space are issues due large diagrams, think to implement some strategy like keeping an incremental difference for each element of a diagram in a std::vector (limit it to 3/5 if objects are big) and call the renderer with the current statuses. I'm not an OpenGL expert, but I think it's the way it's done there. Actually you could 'steal' this strategy from game development best practices, or generally graphics related ones.
One of those strategies could be something like this:
A structure for efficient update, incremental redisplay and undo in graphical editors
Related
I am working on a project where a file must be saved after some operations have been performed on a class's member objects. Sometimes we want to save the file after one operation, sometimes we need to not save it until after a batch of operations have been performed.
My idea is to use a class which basically works like a recursive mutex. Except instead of locking and unlocking a mutex, I want the class to call a method (in this case, save the file) when the last instance of the class in the stack falls out of scope.
Implementing a class which does this is not a problem, but this feels like a generic problem that I just can't find in Boost or STL. Is there a pre-existing standard solution to this problem, or do I need to roll my own class to do it? If so, is my approach the correct one, or is there a better way to solve the problem?
Below is a simple implementation of the kind of behavior I am looking for. It will only print "Hello World!" twice even though DoItOnce() is being called 11 times. I would like to use something like GenericGuard by pulling it from a recognized standard rather than sticking my own implementation in the code base. Is that possible?
#include <iostream>
void Noop (void) { }
void HelloWorld (void) { std::cout << "Hello World!" << std::endl; }
// This is what I imagine a generic implementation would look like...
template <void (*InitFunc)(), void (*DestructFunc)()>
class GenericGuard
{
int & _i;
public:
GenericGuard (int & i) : _i(i) { if (_i++ == 0) { InitFunc(); } }
~GenericGuard () { if (--_i == 0) { DestructFunc(); } }
};
int HelloWorldCounter; // Use a factory class in real-world?
typedef GenericGuard<Noop, HelloWorld> HelloWorldGuard;
void DoSomethingOnce (void)
{
HelloWorldGuard G (HelloWorldCounter);
// Do something
}
void DoItTenTimes (void)
{
HelloWorldGuard G (HelloWorldCounter);
for (int i = 0; i < 10; ++i)
{
DoSomethingOnce();
}
}
int main (void)
{
DoSomethingOnce();
DoItTenTimes();
return 0;
}
You can use a shared_ptr with a custom deleter function.
STL (since c++11): http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr
Boost: http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/shared_ptr.htm#deleter_constructor
Example :
#include <memory>
#include <iostream>
void HelloWorld(void *) { std::cout << "Hello World!" << std::endl; }
class factory
{
public:
static std::shared_ptr<void> get_instance()
{
static std::weak_ptr<void> ref;
if (ref.expired())
{
std::shared_ptr<void> sp{nullptr, HelloWorld};
ref = sp;
return sp;
}
return ref.lock();
}
};
void DoSomethingOnce (void)
{
std::shared_ptr<void> G = factory::get_instance();
// Do something
}
void DoItTenTimes (void)
{
std::shared_ptr<void> G = factory::get_instance();
for (int i = 0; i < 10; ++i)
{
DoSomethingOnce();
}
}
int main(void)
{
DoSomethingOnce();
DoItTenTimes();
return 0;
}
The pattern you're after seems to be wellknown indeed: you're looking to group operations in transactions[1].
Related patterns that come up in my mind are
Command pattern (with the famous Do/Undo example)
Composite pattern (so you can have a command that composes several other commands, forming a tree);
Unit Of Work pattern; this lets you group pending edits and apply them as a group
Software Transactional Memory (which focuses on real atomicity of operations, e.g. with exception safety).
No I'm not a stout advocate of patterns, but I like the concepts it gives you to talk about things: So, what you'd really want is Unit-Of-Work (which could be as simple as grouped Commands) and you want a "Transaction" that automatically applies the changes when destructed.
Depending on your actual application, it might be fine to stick with the mutable object approach that you appear to have now, and just serialize it occasionally. If the application domain becomes slightly more interesting (e.g. with threading, undo and or versioning?) you will quickly find that life gets a lot simpler when you move to a document model that is a graph of references to immutable nodes. This allows you to cheaply "edit" a complex object graph by simply replacing nodes. The nodes being immutable make it safe to share them, even in threaded environments.
I think related to your question is Sean Parent's Seasoning C++ talk. Although this focuses on how to organize your document model, I feel it might be pretty insightful and might give you the "breakthrough" change in point-of-view to make the problem simple again.
[1] which need not be atomic at all in this context, though they might (need to) be in your application domain.
I'm working on a code which needs to be extremely flexible in nature, i.e. especially very easy to extend later also by other people. But I'm facing a problem now about which I do not even know in principal how to properly deal with:
I'm having a rather complex Algorithm, which at some point is supposed to converge. But due to its complexity there are several different criteria to check for convergence, and depending on the circumstances (or input) I would want to have different convergence criteria activated. Also it should easily be possible to create new convergence criteria without having to touch the algorithm itself. So ideally I would like to have an abstract ConvergenceChecker class from which I can inherit and let the algorithm have a vector of those, e.g. like this:
//Algorithm.h (with include guards of course)
class Algorithm {
//...
vector<ConvergenceChecker*> _convChecker;
}
//Algorithm.cpp
void runAlgorithm() {
bool converged=false;
while(true){
//Algorithm performs a cycle
for (unsigned i=0; i<_convChecker.size(); i++) {
// Check for convergence with each criterion
converged=_convChecker[i]->isConverged();
// If this criterion is not satisfied, forget about the following ones
if (!converged) { break; }
}
// If all are converged, break out of the while loop
if (converged) { break; }
}
}
The problem with this is that each ConvergenceChecker needs to know something about the currently running Algorithm, but each one might need to know totally different things from the algorithm. Say the Algorithm changes _foo _bar and _fooBar during each cycle, but one possible ConvergenceChecker only needs to know _foo, another one _foo and _bar, and it might be that some day a ConvergenceChecker needing _fooBar will be implemented. Here are some ways I already tried to solve this:
Give the function isConverged() a large argument list (containing _foo, _bar, and _fooBar). Disadvantages: Most of the variables used as arguments will not be used in most cases, and if the Algorithm would be extended by another variable (or a similar algorithm inherits from it and adds some variables) quite some code would have to be modified. -> possible, but ugly
Give the function isConverged() the Algorithm itself (or a pointer to it) as an argument. Problem: Circular dependency.
Declare isConverged() as a friend function. Problem (among others): Cannot be defined as a member function of different ConvergenceCheckers.
Use an array of function pointers. Does not solve the problem at all, and also: where to define them?
(Just came up with this while writing this question) Use a different class which holds the data, say AlgorithmData having Algorithm as a friend class, then provide the AlgorithmData as a function argument. So, like 2. but maybe getting around circular dependency problems. (Did not test this yet.)
I'd be happy to hear your solutions about this (and problems you see with 5.).
Further notes:
Question title: I'm aware that 'strongly dependent classes' already says that most probably one is doing something very wrong with designing the code, still I guess a lot of people might end up with having that problem and would like to hear possibilities to avoid it, so I'd rather keep that ugly expression.
Too easy?: Actually the problem I presented here was not complete. There will be a lot of different Algorithms in the code inheriting from each other, and the ConvergenceCheckers should of course ideally work in appropriate cases without any further modification even if new Algorithms come up. Feel free to comment on this as well.
Question style: I hope the question is neither too abstract nor too special, and I hope it did not get too long and is understandable. So please also don't hesitate to comment on the way I ask this question so that I can improve on that.
Actually, your solution 5 sounds good.
When in danger of introducing circular dependencies, the best remedy usually is to extract the part that both need, and moving it to a separate entity; exactly as extracting the data used by the algorithm into a separate class/struct would do in your case!
Another solution would be passing your checker an object that provides the current algorithm state in response to parameter names expressed as string names. This makes it possible to separately compile your conversion strategies, because the interface of this "callback" interface stays the same even if you add more parameters to your algorithm:
struct AbstractAlgorithmState {
virtual double getDoubleByName(const string& name) = 0;
virtual int getIntByName(const string& name) = 0;
};
struct ConvergenceChecker {
virtual bool converged(const AbstractAlgorithmState& state) = 0;
};
That is all the implementers of the convergence checker need to see: they implement the checker, and get the state.
You can now build a class that is tightly coupled with your algorithm implementation to implement AbstractAlgorithmState and get the parameter based on its name. This tightly coupled class is private to your implementation, though: the callers see only its interface, which never changes:
class PrivateAlgorithmState : public AbstractAlgorithmState {
private:
const Algorithm &algorithm;
public:
PrivateAlgorithmState(const Algorithm &alg) : algorithm(alg) {}
...
// Implement getters here
}
void runAlgorithm() {
PrivateAlgorithmState state(*this);
...
converged=_convChecker[i]->converged(state);
}
Using a separate data/state structure seems easy enough - just pass it to the checker as a const reference for read-only access.
class Algorithm {
public:
struct State {
double foo_;
double bar_;
double foobar_;
};
struct ConvergenceChecker {
virtual ~ConvergenceChecker();
virtual bool isConverged(State const &) = 0;
}
void addChecker(std::unique_ptr<ConvergenceChecker>);
private:
std::vector<std::unique_ptr<ConvergenceChecker>> checkers_;
State state_;
bool isConverged() {
const State& csr = state_;
return std::all_of(checkers_.begin(),
checkers_.end(),
[csr](std::unique_ptr<ConvergenceChecker> &cc) {
return cc->isConverged(csr);
});
}
};
Maybe the decorator pattern can help in simplifying an (unknown) set of convergence checks. This way you can keep the algorithm itself agnostic to what convergence checks may occur and you don't require a container for all the checks.
You would get something along these lines:
class ConvergenceCheck {
private:
ConvergenceCheck *check;
protected:
ConvergenceCheck(ConvergenceCheck *check):check(check){}
public:
bool converged() const{
if(check && check->converged()) return true;
return thisCheck();
}
virtual bool thisCheck() const=0;
virtual ~ConvergenceCheck(){ delete check; }
};
struct Check1 : ConvergenceCheck {
public:
Check1(ConvergenceCheck* check):ConvergenceCheck(check) {}
bool thisCheck() const{ /* whatever logic you like */ }
};
You can then make arbitrary complex combinations of convergence checks while only keeping one ConvergenceCheck* member in Algorithm. For example, if you want to check two criteria (implemented in Check1 and Check2):
ConvergenceCheck *complex=new Check2(new Check1(nullptr));
The code is not complete, but you get the idea. Additionally, if you are a performance fanatic and are afraid of the virtual function call (thisCheck), you can apply the curiously returning template pattern to eliminate that.
Here is a complete example of decorators to check constraints on an int, to give an idea of how it works:
#include <iostream>
class Check {
private:
Check *check_;
protected:
Check(Check *check):check_(check){}
public:
bool check(int test) const{
if(check_ && !check_->check(test)) return false;
return thisCheck(test);
}
virtual bool thisCheck(int test) const=0;
virtual ~Check(){ delete check_; }
};
class LessThan5 : public Check {
public:
LessThan5():Check(NULL){};
LessThan5(Check* check):Check(check) {};
bool thisCheck(int test) const{ return test < 5; }
};
class MoreThan3 : public Check{
public:
MoreThan3():Check(NULL){}
MoreThan3(Check* check):Check(check) {}
bool thisCheck(int test) const{ return test > 3; }
};
int main(){
Check *morethan3 = new MoreThan3();
Check *lessthan5 = new LessThan5();
Check *both = new LessThan5(new MoreThan3());
std::cout << morethan3->check(3) << " " << morethan3->check(4) << " " << morethan3->check(5) << std::endl;
std::cout << lessthan5->check(3) << " " << lessthan5->check(4) << " " << lessthan5->check(5) << std::endl;
std::cout << both->check(3) << " " << both->check(4) << " " << both->check(5);
}
Output:
0 1 1
1 1 0
0 1 0
I have a pretty simple question about the dynamic_cast operator. I know this is used for run time type identification, i.e., to know about the object type at run time. But from your programming experience, can you please give a real scenario where you had to use this operator? What were the difficulties without using it?
Toy example
Noah's ark shall function as a container for different types of animals. As the ark itself is not concerned about the difference between monkeys, penguins, and mosquitoes, you define a class Animal, derive the classes Monkey, Penguin, and Mosquito from it, and store each of them as an Animal in the ark.
Once the flood is over, Noah wants to distribute animals across earth to the places where they belong and hence needs additional knowledge about the generic animals stored in his ark. As one example, he can now try to dynamic_cast<> each animal to a Penguin in order to figure out which of the animals are penguins to be released in the Antarctic and which are not.
Real life example
We implemented an event monitoring framework, where an application would store runtime-generated events in a list. Event monitors would go through this list and examine those specific events they were interested in. Event types were OS-level things such as SYSCALL, FUNCTIONCALL, and INTERRUPT.
Here, we stored all our specific events in a generic list of Event instances. Monitors would then iterate over this list and dynamic_cast<> the events they saw to those types they were interested in. All others (those that raise an exception) are ignored.
Question: Why can't you have a separate list for each event type?
Answer: You can do this, but it makes extending the system with new events as well as new monitors (aggregating multiple event types) harder, because everyone needs to be aware of the respective lists to check for.
A typical use case is the visitor pattern:
struct Element
{
virtual ~Element() { }
void accept(Visitor & v)
{
v.visit(this);
}
};
struct Visitor
{
virtual void visit(Element * e) = 0;
virtual ~Visitor() { }
};
struct RedElement : Element { };
struct BlueElement : Element { };
struct FifthElement : Element { };
struct MyVisitor : Visitor
{
virtual void visit(Element * e)
{
if (RedElement * p = dynamic_cast<RedElement*>(e))
{
// do things specific to Red
}
else if (BlueElement * p = dynamic_cast<BlueElement*>(e))
{
// do things specific to Blue
}
else
{
// error: visitor doesn't know what to do with this element
}
}
};
Now if you have some Element & e;, you can make MyVisitor v; and say e.accept(v).
The key design feature is that if you modify your Element hierarchy, you only have to edit your visitors. The pattern is still fairly complex, and only recommended if you have a very stable class hierarchy of Elements.
Imagine this situation: You have a C++ program that reads and displays HTML. You have a base class HTMLElement which has a pure virtual method displayOnScreen. You also have a function called renderHTMLToBitmap, which draws the HTML to a bitmap. If each HTMLElement has a vector<HTMLElement*> children;, you can just pass the HTMLElement representing the element <html>. But what if a few of the subclasses need special treatment, like <link> for adding CSS. You need a way to know if an element is a LinkElement so you can give it to the CSS functions. To find that out, you'd use dynamic_cast.
The problem with dynamic_cast and polymorphism in general is that it's not terribly efficient. When you add vtables into the mix, it only get's worse.
When you add virtual functions to a base class, when they are called, you end up actually going through quite a few layers of function pointers and memory areas. That will never be more efficient than something like the ASM call instruction.
Edit: In response to Andrew's comment bellow, here's a new approach: Instead of dynamic casting to the specific element type (LinkElement), instead you have another abstract subclass of HTMLElement called ActionElement that overrides displayOnScreen with a function that displays nothing, and creates a new pure virtual function: virtual void doAction() const = 0. The dynamic_cast is changed to test for ActionElement and just calls doAction(). You'd have the same kind of subclass for GraphicalElement with a virtual method displayOnScreen().
Edit 2: Here's what a "rendering" method might look like:
void render(HTMLElement root) {
for(vector<HTLMElement*>::iterator i = root.children.begin(); i != root.children.end(); i++) {
if(dynamic_cast<ActionElement*>(*i) != NULL) //Is an ActionElement
{
ActionElement* ae = dynamic_cast<ActionElement*>(*i);
ae->doAction();
render(ae);
}
else if(dynamic_cast<GraphicalElement*>(*i) != NULL) //Is a GraphicalElement
{
GraphicalElement* ge = dynamic_cast<GraphicalElement*>(*i);
ge->displayToScreen();
render(ge);
}
else
{
//Error
}
}
}
Operator dynamic_cast solves the same problem as dynamic dispatch (virtual functions, visitor pattern, etc): it allows you to perform different actions based on the runtime type of an object.
However, you should always prefer dynamic dispatch, except perhaps when the number of dynamic_cast you'd need will never grow.
Eg. you should never do:
if (auto v = dynamic_cast<Dog*>(animal)) { ... }
else if (auto v = dynamic_cast<Cat*>(animal)) { ... }
...
for maintainability and performance reasons, but you can do eg.
for (MenuItem* item: items)
{
if (auto submenu = dynamic_cast<Submenu*>(item))
{
auto items = submenu->items();
draw(context, items, position); // Recursion
...
}
else
{
item->draw_icon();
item->setup_accelerator();
...
}
}
which I've found quite useful in this exact situation: you have one very particular subhierarchy that must be handled separately, this is where dynamic_cast shines. But real world examples are quite rare (the menu example is something I had to deal with).
dynamic_cast is not intended as an alternative to virtual functions.
dynamic_cast has a non-trivial performance overhead (or so I think) since the whole class hierarchy has to be walked through.
dynamic_cast is similar to the 'is' operator of C# and the QueryInterface of good old COM.
So far I have found one real use of dynamic_cast:
(*) You have multiple inheritance and to locate the target of the cast the compiler has to walk the class hierarchy up and down to locate the target (or down and up if you prefer). This means that the target of the cast is in a parallel branch in relation to where the source of the cast is in the hierarchy. I think there is NO other way to do such a cast.
In all other cases, you just use some base class virtual to tell you what type of object you have and ONLY THEN you dynamic_cast it to the target class so you can use some of it's non-virtual functionality. Ideally there should be no non-virtual functionality, but what the heck, we live in the real world.
Doing things like:
if (v = dynamic_cast(...)){} else if (v = dynamic_cast(...)){} else if ...
is a performance waste.
Casting should be avoided when possible, because it is basically saying to the compiler that you know better and it is usually a sign of some weaker design decission.
However, you might come in situations where the abstraction level was a bit too high for 1 or 2 sub-classes, where you have the choice to change your design or solve it by checking the subclass with dynamic_cast and handle it in a seperate branch. The trade-of is between adding extra time and risk now against extra maintenance issues later.
In most situations where you are writing code in which you know the type of the entity you're working with, you just use static_cast as it's more efficient.
Situations where you need dynamic cast typically arrive (in my experience) from lack of foresight in design - typically where the designer fails to provide an enumeration or id that allows you to determine the type later in the code.
For example, I've seen this situation in more than one project already:
You may use a factory where the internal logic decides which derived class the user wants rather than the user explicitly selecting one. That factory, in a perfect world, returns an enumeration which will help you identify the type of returned object, but if it doesn't you may need to test what type of object it gave you with a dynamic_cast.
Your follow-up question would obviously be: Why would you need to know the type of object that you're using in code using a factory?
In a perfect world, you wouldn't - the interface provided by the base class would be sufficient for managing all of the factories' returned objects to all required extents. People don't design perfectly though. For example, if your factory creates abstract connection objects, you may suddenly realize that you need to access the UseSSL flag on your socket connection object, but the factory base doesn't support that and it's not relevant to any of the other classes using the interface. So, maybe you would check to see if you're using that type of derived class in your logic, and cast/set the flag directly if you are.
It's ugly, but it's not a perfect world, and sometimes you don't have time to refactor an imperfect design fully in the real world under work pressure.
The dynamic_cast operator is very useful to me.
I especially use it with the Observer pattern for event management:
#include <vector>
#include <iostream>
using namespace std;
class Subject; class Observer; class Event;
class Event { public: virtual ~Event() {}; };
class Observer { public: virtual void onEvent(Subject& s, const Event& e) = 0; };
class Subject {
private:
vector<Observer*> m_obs;
public:
void attach(Observer& obs) { m_obs.push_back(& obs); }
public:
void notifyEvent(const Event& evt) {
for (vector<Observer*>::iterator it = m_obs.begin(); it != m_obs.end(); it++) {
if (Observer* const obs = *it) {
obs->onEvent(*this, evt);
}
}
}
};
// Define a model with events that contain data.
class MyModel : public Subject {
public:
class Evt1 : public Event { public: int a; string s; };
class Evt2 : public Event { public: float f; };
};
// Define a first service that processes both events with their data.
class MyService1 : public Observer {
public:
virtual void onEvent(Subject& s, const Event& e) {
if (const MyModel::Evt1* const e1 = dynamic_cast<const MyModel::Evt1*>(& e)) {
cout << "Service1 - event Evt1 received: a = " << e1->a << ", s = " << e1->s << endl;
}
if (const MyModel::Evt2* const e2 = dynamic_cast<const MyModel::Evt2*>(& e)) {
cout << "Service1 - event Evt2 received: f = " << e2->f << endl;
}
}
};
// Define a second service that only deals with the second event.
class MyService2 : public Observer {
public:
virtual void onEvent(Subject& s, const Event& e) {
// Nothing to do with Evt1 in Service2
if (const MyModel::Evt2* const e2 = dynamic_cast<const MyModel::Evt2*>(& e)) {
cout << "Service2 - event Evt2 received: f = " << e2->f << endl;
}
}
};
int main(void) {
MyModel m; MyService1 s1; MyService2 s2;
m.attach(s1); m.attach(s2);
MyModel::Evt1 e1; e1.a = 2; e1.s = "two"; m.notifyEvent(e1);
MyModel::Evt2 e2; e2.f = .2f; m.notifyEvent(e2);
}
Contract Programming and RTTI shows how you can use dynamic_cast to allow objects to advertise what interfaces they implement. We used it in my shop to replace a rather opaque metaobject system. Now we can clearly describe the functionality of objects, even if the objects are introduced by a new module several weeks/months after the platform was 'baked' (though of course the contracts need to have been decided on up front).
I have a set of classes that describe a set of logical boxes that can hold things and do things to them. I have
struct IBox // all boxes do these
{
....
}
struct IBoxCanDoX // the power to do X
{
void x();
}
struct IBoxCanDoY // the power to do Y
{
void y();
}
I wonder what is the 'best' or maybe its just 'favorite' idiom for a client of these classes to deal with these optional capabilities
a)
if(typeid(box) == typeid(IBoxCanDoX))
{
IBoxCanDoX *ix = static_cast<IBoxCanDoX*>(box);
ix->x();
}
b)
IBoxCanDoX *ix = dynamic_cast<IBoxCanDoX*>(box);
if(ix)
{
ix->x();
}
c)
if(box->canDoX())
{
IBoxCanDoX *ix = static_cast<IBoxCanDoX*>(box);
ix->x();
}
d) different class struct now
struct IBox
{
void x();
void y();
}
...
box->x(); /// ignored by implementations that dont do x
e) same except
box->x() // 'not implemented' exception thrown
f) explicit test function
if(box->canDoX())
{
box->x();
}
I am sure there are others too.
EDIT:
Just to make the use case clearer
I am exposing this stuff to end users via interactive ui. They can type 'make box do X'. I need to know if box can do x. Or I need to disable the 'make current box do X' command
EDIT2: Thx to all answerers
as Noah Roberts pointed out (a) doesnt work (explains some of my issues !).
I ended up doing (b) and a slight variant
template<class T>
T* GetCurrentBox()
{
if (!current_box)
throw "current box not set";
T* ret = dynamic_cast<T*>(current_box);
if(!ret)
throw "current box doesnt support requested operation";
return ret;
}
...
IBoxCanDoX *ix = GetCurrentBox<IBoxCanDoX>();
ix->x();
and let the UI plumbing deal nicely with the exceptions (I am not really throwing naked strings).
I also intend to explore Visitor
I suggest the Visitor pattern for double-dispatch problems like this in C++:
class IVisitor
{
public:
virtual void Visit(IBoxCanDoX *pBox) = 0;
virtual void Visit(IBoxCanDoY *pBox) = 0;
virtual void Visit(IBox* pBox) = 0;
};
class IBox // all boxes do these
{
public:
virtual void Accept(IVisitor *pVisitor)
{
pVisitor->Visit(this);
}
};
class BoxCanDoY : public IBox
{
public:
virtual void Accept(IVisitor *pVisitor)
{
pVisitor->Visit(this);
}
};
class TestVisitor : public IVisitor
{
public:
// override visit methods to do tests for each type.
};
void Main()
{
BoxCanDoY y;
TestVisitor v;
y.Accept(&v);
}
Of the options you've given, I'd say that b or d are "best". However, the need to do a lot of this sort of thing is often indicative of a poor design, or of a design that would be better implemented in a dynamically typed language rather than in C++.
If you are using the 'I' prefix to mean "interface" as it would mean in Java, which would be done with abstract bases in C++, then your first option will fail to work....so that one's out. I have used it for some things though.
Don't do 'd', it will pollute your hierarchy. Keep your interfaces clean, you'll be glad you did. Thus a Vehicle class doesn't have a pedal() function because only some vehicles can pedal. If a client needs the pedal() function then it really does need to know about those classes that can.
Stay way clear of 'e' for the same reason as 'd' PLUS that it violates the Liskov Substitution Principle. If a client needs to check that a class responds to pedal() before calling it so that it doesn't explode then the best way to do that is to attempt casting to an object that has that function. 'f' is just the same thing with the check.
'c' is superfluous. If you have your hierarchy set up the way it should be then casting to ICanDoX is sufficient to check if x can do X().
Thus 'b' becomes your answer from the options given. However, as Gladfelter demonstrates, there are options you haven't considered in your post.
Edit note: I did not notice that 'c' used a static_cast rather than dynamic. As I mention in an answer about that, the dynamic_cast version is cleaner and should be preferred unless specific situations dictate otherwise. It's similar to the following options in that it pollutes the base interface.
Edit 2: I should note that in regard to 'a', I have used it but I don't use types statically like you have in your post. Any time I've used typeid to split flow based on type it has always been based on something that is registered during runtime. For example, opening the correct dialog to edit some object of unknown type: the dialog governors are registered with a factory based on the type they edit. This keeps me from having to change any of the flow control code when I add/remove/change objects. I generally wouldn't use this option under different circumstances.
A and B require run time type identification(RTTI) and might be slower if you are doing a lot checks. Personally I don't like the solutions of "canDoX" methods, if situations like this arise the design probably needs an upgrade because you are exposing information that is not relevant to the class.
If you only need to execute X or Y, depending on the class, I would go for a virtual method in IBox which get overridden in subclasses.
class IBox{
virtual void doThing();
}
class IBoxCanDoX: public IBox{
void doThing() { doX(); }
void doX();
}
class IBoxCanDoY: public IBox{
void doThing() { doY(); }
void doY();
}
box->doThing();
If that solution is not applicable or you need more complex logic, then look at the Visitor design pattern. But keep in mind that the visitor pattern is not very flexible when you add new classes regularly or methods change/are added/are removed (but that also goes true for your proposed alternatives).
If you are trying to call either of these classes actions from contingent parts of code, you I would suggest you wrap that code in a template function and name each class's methods the same way to implement duck typing, thus your client code would look like this.
template<class box>
void box_do_xory(box BOX){
BOX.xory();
}
There is no general answer to your question. Everything depends. I can say only that:
- don't use a), use b) instead
- b) is nice, requires least code, no need for dummy methods, but dynamic_cast is a little slow
- c) is similar to b) but it is faster (no dynamic_cast) and requires more memory
- e) has no sense, you still need to discover if you can call the method so the exception is not thrown
- d) is better then f) (less code to write)
- d) e) and f) produce more garbage code then others, but are faster and less memory consuming
I assume that you will not only be working with one object of one type here.
I would lay out the data that you are working with and try to see how you can lay it out in memory in order to do data-driven programming. A good layout in memory should reflect the way that you store the data in your classes and how the classes are layed out in memory. Once you have that basic design structured (shouldn't take more than a napkin), I would begin organizing the objects into lists dependent on the operations that you plan to do on the data. If you plan to do X() on a collection of objects { Y } in the subset X, I would probably make sure to have a static array of Y that I create from the beginning. If you wish to access the entire of X occasionally, that can be arranged by collecting the lists into a dynamic list of pointers (using std::vector or your favorite choice).
I hope that makes sense, but once implemented it gives simple straight solutions that are easy to understand and easy to work with.
There is a generic way to test if a class supports a certain concept and then to execute the most appropriate code. It uses SFINAE hack. This example is inspired by Abrahams and Gurtovoy's "C++ Template Metaprogramming" book. The function doIt will use x method if it is present, otherwise it will use y method. You can extend CanDo structure to test for other methods as well. You can test as many methods as you wish, as long as the overloads of doIt can be resolved uniquely.
#include <iostream>
#include <boost/config.hpp>
#include <boost/utility/enable_if.hpp>
typedef char yes; // sizeof(yes) == 1
typedef char (&no)[2]; // sizeof(no) == 2
template<typename T>
struct CanDo {
template<typename U, void (U::*)()>
struct ptr_to_mem {};
template<typename U>
static yes testX(ptr_to_mem<U, &U::x>*);
template<typename U>
static no testX(...);
BOOST_STATIC_CONSTANT(bool, value = sizeof(testX<T>(0)) == sizeof(yes));
};
struct DoX {
void x() { std::cout << "doing x...\n"; }
};
struct DoAnotherX {
void x() { std::cout << "doing another x...\n"; }
};
struct DoY {
void y() { std::cout << "doing y...\n"; }
};
struct DoAnotherY {
void y() { std::cout << "doing another y...\n"; }
};
template <typename Action>
typename boost::enable_if<CanDo<Action> >::type
doIt(Action* a) {
a->x();
}
template <typename Action>
typename boost::disable_if<CanDo<Action> >::type
doIt(Action* a) {
a->y();
}
int main() {
DoX doX;
DoAnotherX doAnotherX;
DoY doY;
DoAnotherY doAnotherY;
doIt(&doX);
doIt(&doAnotherX);
doIt(&doY);
doIt(&doAnotherY);
}
In a project I'm working on in C++, I need to create objects for messages as they come in over the wire. I'm currently using the factory method pattern to hide the creation of objects:
// very psuedo-codey
Message* MessageFactory::CreateMessage(InputStream& stream)
{
char header = stream.ReadByte();
switch (header) {
case MessageOne::Header:
return new MessageOne(stream);
case MessageTwo::Header:
return new MessageTwo(stream);
// etc.
}
}
The problem I have with this is that I'm lazy and don't like writing the names of the classes in two places!
In C# I would do this with some reflection on first use of the factory (bonus question: that's an OK use of reflection, right?) but since C++ lacks reflection, this is off the table. I thought about using a registry of some sort so that the messages would register themselves with the factory at startup, but this is hampered by the non-deterministic (or at least implementation-specific) static initialization order problem.
So the question is, is it possible to implement this type of factory in C++ while respecting the open/closed principle, and how?
EDIT: Apparently I'm overthinking this. I intended this question to be a "how would you do this in C++" since it's really easy to do with reflection in other languages.
I think that the open/closed approach and DRY are good principles. But they are not sacred. The goal should be making the code reliable and maintainable. If you have to perform unnatural acts to adhere to O/C or DRY, then you may simply be making your code needlessly more complex with no material benefit.
Here is something I wrote a few years ago on how I make these judgment calls.
You do not need to make your code follow every possible principle simultaneously. The aim should be to stick to as many of those paradigms as possible and no more. Do not over-engineer your solution -- you are likely to end up with spaghetti code otherwise.
I have answered in another SO question about C++ factories. Please see there if a flexible factory is of interest. I try to describe an old way from ET++ to use macros which has worked great for me.
The method is macro based and are easily extensible.
ET++ was a project to port old MacApp to C++ and X11. In the effort of it Eric Gamma etc started to think about Design Patterns
You could convert classes that create messages (MessageOne, MessageTwo ...) into message factories and register them with top level MessageFactory on initialization.
Message factory could hold map of MessageX::Header -> instance of MessageXFactory kind of map.
In CreateMessage you would find instance of MessageXFactory based on message header, retrieve the reference to MessageXFactory and then call it's method that would return instance of the actual MessageX.
With new messages you no longer have to modify the 'switch', you just need to add an instance of new MessageXFactory to the TopMessageFactory.
example:
#include <iostream>
#include <map>
#include <string>
using namespace std;
struct Message
{
static const int id = 99;
virtual ~Message() {}
virtual int msgId() { return id; }
};
struct NullMessage : public Message
{
static const int id = 0;
virtual int msgId() { return id; }
};
struct MessageOne : public Message
{
static const int id = 1;
virtual int msgId() { return id; }
};
struct MessageTwo : public Message
{
static const int id = 2;
virtual int msgId() { return id; }
};
struct MessageThree : public Message
{
static const int id = 3;
virtual int msgId() { return id; }
};
struct IMessageFactory
{
virtual ~IMessageFactory() {}
virtual Message * createMessage() = 0;
};
struct MessageOneFactory : public IMessageFactory
{
MessageOne * createMessage()
{
return new MessageOne();
}
};
struct MessageTwoFactory : public IMessageFactory
{
MessageTwo * createMessage()
{
return new MessageTwo();
}
};
struct TopMessageFactory
{
Message * createMessage(const string& data)
{
map<string, IMessageFactory*>::iterator it = msgFactories.find(data);
if (it == msgFactories.end()) return new NullMessage();
return (*it).second->createMessage();
}
bool registerFactory(const string& msgId, IMessageFactory * factory)
{
if (!factory) return false;
msgFactories[msgId] = factory;
return true;
}
map<string, IMessageFactory*> msgFactories;
};
int main()
{
TopMessageFactory factory;
MessageOneFactory * mof = new MessageOneFactory();
MessageTwoFactory * mtf = new MessageTwoFactory();
factory.registerFactory("one", mof);
factory.registerFactory("two", mtf);
Message * msg = factory.createMessage("two");
cout << msg->msgId() << endl;
msg = factory.createMessage("one");
cout << msg->msgId() << endl;
}
First, your system is not so open ended, since you switch on an 8-bit char, so your message type count won't exceed 256 ;-)
Just joking apart, this is a situation I'd use a little templated factory class (stateless if you put your char message type in a non-class template arg, or with just that char as state) that accepts your stream& and does the new on its T template arg, passing the stream& and returning it. You'll need a little registrar class to declare as static with global scope, and register the concrete T-instantiated factory (via an abstract base class pointer) with a manager (we have a generic one that takes a "factory domain" key). In your case I wouldn't use a map but directly an 256 "slot" array to put the factory_base* in.
One you have the factory framework in place, it's easy and reusable. --DD