This have been asked in the interview.
How to write own dynamic_cast. I think, on the basis of typeid\'s name function.
Now how to implement own typid? I hav
ONe way is to declare a static identifier (an integer for example) which defines the class ID. In the class you could implement both static and scoped routines wich returns the class identifier (Remeber to mark routines virtual).
The static identifier shall be initialized at application initialization. One way is to call an InitializeId routine for each class, but this mean that the class names must be known, and the initialization code shall be modified each time the class hierarchy is modified. Another way is to check for valid identifier at construction time, but this introduces an overhead since each time a class is constructed the check is executed, but only the first time is usefull (additionally if no class is constructed, the static routine cannot be usefull since the identifier is never initialized).
A fair implementation could be a template class:
template
class ClassId
{
public:
static int GetClassId() { return (sClassId); }
virtual int GetClassId() const { return (sClassId); }
template static void StateDerivation() {
gClassMap[ClassId::GetClassId()].push_back(ClassId::GetClassId());
}
template const U DynamicCast() const {
std::map>::const_iterator it = gClassMap.find(ClassId); // Base class type, with relative derivations declared with StateDerivation()
int id = ClassId::GetClassId();
if (id == ClassId::GetClassId()) return (static_cast(this));
while (it != gClassMap.end()) {
for (std::list::const_iterator = pit->second.begin(), pite = it->second->end(); pit != pite; pit++) {
if ((*pit) == id) return (static_cast(this));
// ... For each derived element, iterate over the stated derivations.
// Easy to implement with a recursive function, better if using a std::stack to avoid recursion.
}
}
return (null);
}
private:
static int sClassId;
}
#define CLASS_IMP(klass) static int ClassId::sClassId = gClassId++;
// Global scope variables
static int gClassId = 0;
static std::map> gClassMap;
CLASS_IMP shall be defined in for each class deriving from ClassId, and gClassId and gClassMap shall be visible at global scope.
The available class identifiers are keeped by a single static integer variable accessible by all classes (a base class ClassID or a global variable), which is incremented each time a new class identifier is assigned.
To represents the class hierarchy is sufficient a map between the class identifier and its derived classes. To know whether any class can be casted to a specific class, iterate over the map and check declare derivations.
There are many difficulties to face... use of references! virtual derivations! bad casting! Bad class type mapping initialization will lead to casting errors...
Relationships between classes shall be defined manually, hardcoded with the initialization routine. This allow to determine whether a class derived from, or whether two classes as a common derivation.
class Base : ClassId { }
#define CLASS_IMP(Base);
class Derived : public Base, public ClassId { }
#define CLASS_IMP(Derived);
class DerivedDerived : public Derived, public ClassId { }
#define CLASS_IMP(DerivedDerived);
static void DeclareDerivations()
{
ClassId ::StateDerivation();
ClassId::StateDerivation();
}
Personally I agree with "there is a reason if compilers implements dynamic_cast"; probably the compiler do the things better (especially with respect of the example code!).