I'm trying to create an overloaded function that will be called with the dynamic type of an object. I try to do this without interfering with the actual class structure underneath, as I don't have direct access (i.e. I cannot add virtual methods, etc.)
As a concrete example, let's think of an AST class structure that looks somewhat like this:
class ASTNode {}; // this one is fully abstract; i.e. there's a virtual void method() = 0; class Assignment : ASTNode {}; class Expression : ASTNode {}; class StringExpr : Expression {}; class MathExpr : Expression {};
I want to write a function act
that will take an instance of ASTNode
as parameter and, depending on its actual dynamic type do something different. The call will be something like this
std::shared_ptr<ASTNode> parsedAST = get_a_parsed_ASTNode(); // ... received from some parser or library
act(parsedAST);
Then, I want to act, depending on the dynamic type of the ASTNode
.
void act(std::shared_ptr<MathExpr> expr) { // Do something with Math expressions, e.g. evaluate their value }; void act(std::shared_ptr<StringExpr> expr) { // Do something with String expressions, e.g. write their value to the log }; void act(std::shared_ptr<Expression> expr) { // do something with other types of expressions (e.g. Boolean expressions) };
Currently though, I cannot call since they dynamic type will be maybe not the ``most concrete type''. Instead, I have to manually create a dispatcher manually as follows, but the method is a bit silly in my opinion, since it does literally nothing else but dispatch.
void act(std::shared_ptr<ASTNode> node_ptr) { if(std::shared_ptr<MathExpr> derived_ptr = std::dynamic_pointer_cast<MathExpr>(node_ptr)) { act(derived_ptr); } else if(std::shared_ptr<StringExpr> derived_ptr = std::dynamic_pointer_cast<StringExpr>(node_ptr)) { act(derived_ptr); } else if(std::shared_ptr<Expression> derived_ptr = std::dynamic_pointer_cast<Expression>(node_ptr)) { // do something with generic expressions. Make sure that this is AFTER the more concrete if casts } else if( ... ) // more of this { } // more else if else { // default action or raise invalid argument exception or so... } };
This is especially annoying & error-prone since my class hierarchy has many (> 20) different concrete classes that can be instantiated. Also, I have various act
-functions, and when I refactor things (e.g. add an act
for an additional type), I have to make sure to pay attention to the correct order of if(dynamic_pointer_cast)
within the dispatcher. Also it's not that stable, since a change in the underlying class hierarchy will require me to change every dispatcher directly, rather than just the specific act
functions.
Is there a better / smarter solution? Evidently I'd appreciate "native" solutions, but I'm willing to consider libraries too.
Aucun commentaire:
Enregistrer un commentaire