The simplest solution is to do exactly what you suggested. Starting from:
std::string gate =
dynamic_cast<AND*>(pComponent) != nullptr ? "AND" :
dynamic_cast<NAND*>(pComponent) != nullptr ? "NAND" :
dynamic_cast<NOR*>(pComponent) != nullptr ? "NOR" :
dynamic_cast<NOT*>(pComponent) != nullptr ? "NOT" :
dynamic_cast<OR*>(pComponent) != nullptr ? "OR" :
dynamic_cast<XNOR*>(pComponent) != nullptr ? "XNOR" :
dynamic_cast<XOR*>(pComponent) != nullptr ? "XOR" : ""
;
You want a virtual method pComponent->get_gate()
that evaluates to "AND"
in one case, "NAND"
in another, and so on. What is the type of "AND"
, "NAND"
, and so on? It's const char *
. (Yes, yes, technically it's char[4]
and char[5]
respectively, but not for our purposes here. :)) So:
class Node {
public:
virtual const char *get_gate() const { return ""; }
};
class AND : public Node {
public:
const char *get_gate() const override { return "AND"; }
};
std::string gateName(Node *pComponent) {
return pComponent->get_gate();
}
However, there's an even simpler approach, if you just want an identifying string and don't care that it's implementation-defined. Try this:
class Node {
public:
virtual ~Node() = default;
};
class AND : public Node {};
std::string gateName(Node *pComponent) {
return typeid(*pComponent).name();
}
On Linux/Unix/OS X platforms using Clang or GCC, this gives the strings "4Node"
and "3AND"
; that is, it gives the mangled class names. On Visual Studio, it gives the strings "class Node"
and "class AND"
.
Using a virtual function get_gate
will be marginally faster than the typeid
approach (by literally 1 or 2 machine instructions). So it's just a question of how quick-and-dirty you want to be. Since you care enough to ask here, you should probably spend the extra time and lines-of-code to do the get_gate
approach; it'll be easier to understand down the road.
Even sticking with the multi-way-branch approach, you'll find that it's much faster to use typeid
than to use dynamic_cast
, on current library implementations.
std::string gate =
typeid(*pComponent) == typeid(AND) ? "AND" :
typeid(*pComponent) == typeid(NAND) ? "NAND" :
typeid(*pComponent) == typeid(NOR) ? "NOR" :
typeid(*pComponent) == typeid(NOT) ? "NOT" :
typeid(*pComponent) == typeid(OR) ? "OR" :
typeid(*pComponent) == typeid(XNOR) ? "XNOR" :
typeid(*pComponent) == typeid(XOR) ? "XOR" : ""
;
This has different behavior from the original if for example NAND
inherits from AND
; but I'm sure from context that that's not the case.
This would be a decent use for X-Macros.
std::string gateName(Node *pComponent) {
return (
#define X(K) typeid(pComponent) == typeid(K) ? #K :
#include "gate-types.h"
#undef X
""
);
}