(re)implement dynamic_cast - c++

I am working in an ARM7 embedded environment. The compiler I am using does not support the full C++ functionality. One feature it does NOT support is dynamic type casting.
Is there a way to implement dynamic_cast<>()?
I looked for code using Google, but no luck so far. Any ideas? Any links?
UPDATE:
Due to the comments... I'm using the ARM(R) IAR C/C++ Compiler.

dynamic_cast is useful when casting away from the base class, something to be done as little as possible.
Assuming the instances when you want to do this are limited, then a virtual function like GetMessageType() in a base class returning a different value in each derived class will let you know what to static_cast down to.

Take a look at the COM concepts -- objects there have a method to return a pointer to a specific interface that is selected by an identifier not built into the compiler (in COM's case, a UUID).
Depending on your application, a simple integer may do:
class castable {
virtual bool cast_to(int desttype) = 0;
};
class type1 : public castable { public: static int const type = 1; };
class type2 : public castable { public: static int const type = 2; };
class impl : public type1, public type2 {
virtual void *cast_to(int desttype) {
switch(desttype) {
case type1::type: return static_cast<type1 *>(this);
case type2::type: return static_cast<type2 *>(this);
default: return 0;
}
}
};
Then, if templates work correctly:
template<typename T> T my_dynamic_cast(castable *obj) {
return reinterpret_cast<T>(obj.cast_to(T::type));
}
You can then create objects normally, and cast between base class pointers:
impl im;
type1 *t1 = &im; // Implicit, as it is a base class
type2 *t2 = my_dynamic_cast<type2 *>(t1);
The only difficulty here is assigning the identifiers.

It really depends exactly how much of dynamic_cast functionality you need.
Most often, I see dynamic_cast used to perform a checked conversion: dynamic_cast<Derived*>(p) will return 0 if ultimately p real type is not Derived*...
... but even this is quite complicated:
What if p is really EvenMoreDerived and not just Derived ?
What is p inherits from Base multiple times ?
And it can get even more hairy:
static_cast is not able to cross virtual inheritance boundaries.
static_cast is not suitable for cross-branches conversions (you have to pass through the common ancestor)
static_cast cannot emulate the dynamic_cast<void*>() conversion.
So, if you want a simple barebone functionality of checked conversion up the inheritance tree in case of single inheritance without virtual thrown in, then you can actually implement it in user-land.
Otherwise, without RTTI support, you will be quite stuck.
Example of simple (dumb ?) implementation, beginning with the support from the class hierarchy:
class Base {
public:
typedef size_t ID;
virtual ID getID() const = 0;
protected:
static ID NextID() { static ID = 0; return ID++; }
// much more stuff
};
class Derived: public Base {
public:
static ID GetID() { static ID id = Base::NextID(); return id; }
virtual ID getID() const { return GetID(); }
};
We can leverage this with:
template <typename To>
To* dyn_cast(Base* b) {
if (b and b->getID() == To::GetID()) { return static_cast<To*>(b); }
return 0;
}
However, this only work for one level. So, if MoreDerived inherits from Derived then:
MoreDerived md;
assert(dyn_cast<Derived>(&md)); // failure ...
so it really gets tricky here.
A possible approach is to check from the top of the hierarchy, to the bottom.
class Base {
public:
template <typename To>
bool isa() const {
return this->match(To::GetID());
}
protected:
typedef size_t ID;
static ID NextID() { static ID id = 0; return id++; }
virtual bool match(ID) const { return false; }
};
class Derived: public Base {
public:
static ID GetID() { static ID id = NextID(); return id; }
protected:
virtual bool match(ID id) const { return id == GetID() || Base::match(id); }
};
class MostDerived: public Derived {
public:
static ID GetID() { static ID id = NextID(); return id; }
protected:
virtual bool match(ID id) const { return id == GetID() || Derived::match(id); }
};
Slightly more complex, but now:
template <typename To, typename From>
To const* dyn_cast(From const* f) {
if (f and f->template isa<To>()) { return static_cast<To const*>(f); }
return 0;
}
template <typename To, typename From>
To* dyn_cast(From* f) { return const_cast<To*>(dyn_cast<To>((From const*)f)); }
Test case:
int main() {
Derived derived; MostDerived mostDerived;
Base* d = &derived, * md = &mostDerived;
if (dyn_cast<Derived>(d)) { std::cout << "Derived -> Derived: ok\n"; }
else { std::cout << "Derived -> Derived: ko\n"; }
if (dyn_cast<MostDerived>(md)) { std::cout << "MostDerived -> MostDerived : ok\n"; }
else { std::cout << "MostDerived -> MostDerived : ko\n"; }
if (dyn_cast<Derived>(md)) { std::cout << "MostDerived -> Derived : ok\n"; }
else { std::cout << "MostDerived -> Derived : ko\n"; }
if (dyn_cast<MostDerived>(d)) { std::cout << "Derived -> MostDerived: ko\n"; }
else { std::cout << "Derived -> MostDerived: ok\n"; }
}
In action at ideone.
It is still very incomplete compared to a true dynamic_cast though. But it should cover most uses already.

Isn't it possible to just cast your pointer and start using it as the other type of object?
Foo* f = new Foo();
f.baz();
Bar* b = (Bar*)f;
b.bop();

Related

How to convert/use the run time variable in compile time expression?

I have the following situation (live code : https://gcc.godbolt.org/z/d8jG9bs9a):
#include <iostream>
#include <type_traits>
#define ENBALE true // to enable disable test solutions
enum struct Type : unsigned { base = 0, child1, child2, child3 /* so on*/ };
// CRTP Base
template<typename Child> struct Base {
void doSomething() { static_cast<Child*>(this)->doSomething_Impl(); }
private:
Base() = default;
friend Child;
};
struct Child1 : public Base<Child1> {
void doSomething_Impl() { std::cout << "Child1 implementation\n"; }
};
struct Child2 : public Base<Child2> {
void doSomething_Impl() { std::cout << "Child2 implementation\n"; }
};
struct Child3 : public Base<Child3> {
void doSomething_Impl() { std::cout << "Child3 implementation\n"; }
};
// ... so on
class SomeLogicClass
{
Type mClassId{ Type::base };
Child1 mChild1;
Child2 mChild2;
Child3 mChild3;
public:
Type getId() const { return mClassId; }
void setId(Type id) { mClassId = id; } // run time depended!
#if ENBALE // Solution 1 : simple case
/*what in C++11?*/ getInstance()
{
switch (mClassId)
{
case Type::child1: return mChild1;
case Type::child2: return mChild2;
case Type::child3: return mChild3;
default: // error case!
break;
}
}
#elif !ENBALE // Solution 2 : SFINAE
template<Type ID>
auto getInstance() -> typename std::enable_if<ID == Type::child1, Child1&>::type { return mChild1; }
template<Type ID>
auto getInstance() -> typename std::enable_if<ID == Type::child2, Child2&>::type { return mChild2; }
template<Type ID>
auto getInstance() -> typename std::enable_if<ID == Type::child3, Child3&>::type { return mChild3; }
#endif
};
void test(SomeLogicClass& ob, Type id)
{
ob.setId(id);
#if ENBALE // Solution 1
auto& childInstance = ob.getInstance();
#elif !ENBALE // Solution 2
auto& childInstance = ob.getInstance<ob.getId()>();
#endif
childInstance.doSomething(); // calls the corresponding implementations!
}
int main()
{
SomeLogicClass ob;
test(ob, Type::child1);
test(ob, Type::child2);
test(ob, Type::child3);
}
The problem is that the child class selection (to which the doSomething_Impl() must be called), should be taken place by deciding upon a run time variable mClassId of the SomeLogicClass.
The only two possible solutions I can think of are a normal switch case and SFINAE the member functions, as described in the above minimal example. As noted in the comments in the above code, both can't get work, for the reasons
Solution 1: the member function must have a unique return type
Solution 2: SFINAE required a compile time expression to decide which overload to be chosen.
Update
The std::variant(as mentioned by #lorro) would be the easiest solution here. However, require C++17 support.
However, I would like to know if we got some way around which works under the compiler flag c++11?
Note: I am working with a code-base, where external libs such as boost, can not be used, and the CRTP class structure is mostly untouchable.
Since you are restricted to C++11 and are not allowed to use external libraries such as boost::variant, an alternative would be to reverse the logic: Do not attempt to return the child type but instead pass in the operation to perform on the child. Your example could become this (godbolt):
#include <iostream>
#include <type_traits>
enum struct Type : unsigned { base = 0, child1, child2, child3 /* so on*/ };
// CRTP Base
template<typename Child> struct Base {
void doSomething() { static_cast<Child*>(this)->doSomething_Impl(); }
private:
Base() = default;
friend Child;
};
struct Child1 : public Base<Child1> {
void doSomething_Impl() { std::cout << "Child1 implementation\n"; }
};
struct Child2 : public Base<Child2> {
void doSomething_Impl() { std::cout << "Child2 implementation\n"; }
};
struct Child3 : public Base<Child3> {
void doSomething_Impl() { std::cout << "Child3 implementation\n"; }
};
// ... so on
class SomeLogicClass
{
Type mClassId{ Type::base };
Child1 mChild1;
Child2 mChild2;
Child3 mChild3;
// ... child3 so on!
public:
Type getId() const { return mClassId; }
void setId(Type id) { mClassId = id; } // run time depended!
template <class Func>
void apply(Func func)
{
switch (mClassId){
case Type::child1: func(mChild1); break;
case Type::child2: func(mChild2); break;
case Type::child3: func(mChild3); break;
default: // error case!
break;
}
}
};
struct DoSomethingCaller
{
template <class T>
void operator()(T & childInstance){
childInstance.doSomething();
}
};
void test(SomeLogicClass& ob, Type id)
{
ob.setId(id);
ob.apply(DoSomethingCaller{});
// Starting with C++14, you can also simply write:
//ob.apply([](auto & childInstance){ childInstance.doSomething(); });
}
int main()
{
SomeLogicClass ob;
test(ob, Type::child1);
test(ob, Type::child2);
test(ob, Type::child3);
}
Notice how the new function apply() replaces your getInstance(). But instead of attempting to return the child type, it accepts some generic operation that it applies to the correct child. The functor passed in needs to cope (i.e. compile) with all possible child types. Since all of them have a doSomething() method, you can simply use a templated functor (DoSomethingCaller). Before C++14, unfortunately, it cannot simply be a polymorphic lambda but needs to be a proper struct (DoSomethingCaller) outside of the function.
If you care to do so, you can also restrict DoSomethingCaller to the CRTP base class Base<T>:
struct DoSomethingCaller
{
template <class T>
void operator()(Base<T> & childInstance){
childInstance.doSomething();
}
};
which might make it a bit more readable.
Depending on how strict the "no external libraries" restriction is, maybe only boost is not allowed but a single external header (that can be simply included in the code base as any other header file) would be possible? If yes, you might want to also have a look at variant-lite. It aims to be a C++98/C++11 compatible replacement for std::variant.
I recognize here the Bridge pattern in your CRTP code base, although done badly in my opinion. But anyway, if you can't touch that code then you should implement a second bridge code. Fortunately, with templates this won't be that hard.
Here is the code (godbold):
#include <iostream>
enum struct Type : unsigned { base = 0, child1, child2, child3 /* so on*/ };
// CRTP Base
template<typename Child> struct Base {
void doSomething() { static_cast<Child*>(this)->doSomething_Impl(); }
private:
Base() = default;
friend Child;
};
struct Child1 : public Base<Child1> {
void doSomething_Impl() { std::cout << "Child1 implementation\n"; }
};
struct Child2 : public Base<Child2> {
void doSomething_Impl() { std::cout << "Child2 implementation\n"; }
};
struct Child3 : public Base<Child3> {
void doSomething_Impl() { std::cout << "Child3 implementation\n"; }
};
// ... so on
class CommonInterface {
public:
virtual void doSomething() = 0;
};
template<class Child>
class ChildCaller : public CommonInterface {
private:
Child child;
public:
virtual void doSomething() {
child.doSomething_Impl();
}
};
class SomeLogicClass
{
Type mClassId{ Type::base };
ChildCaller<Child1> mChild1;
ChildCaller<Child2> mChild2;
ChildCaller<Child3> mChild3;
CommonInterface* currentChild;
public:
Type getId() const { return mClassId; }
void setId(Type id) {
mClassId = id;
switch(id) {
case Type::child1:
currentChild = &mChild1;
break;
case Type::child2:
currentChild = &mChild2;
break;
case Type::child3:
currentChild = &mChild3;
break;
default:
currentChild = nullptr; // or anything you want
}
}
void doSomething() {
currentChild->doSomething();
}
};
void test(SomeLogicClass& ob, Type id)
{
ob.setId(id);
ob.doSomething(); // calls the corresponding implementations!
}
int main() {
SomeLogicClass ob;
test(ob, Type::child1);
test(ob, Type::child2);
test(ob, Type::child3);
}
I omitted error checking here and there, so the code is more readable.
It is not clear if you want one element or one of each.
If you need one of each, SomeLogicClass should have a std::tuple<Class1, Class2, Class3>. This stores 'one of each', also provides std::get<>(), which returns element i. Thus, getInstance() can essentially delegate to std::get<ID>().
If you need one element of either type, SomeLogicClass should have a std::variant<Class1, Class2, Class3>. This stores the kind of the active element and the element itself. You can either use std::get<>() for it, or - better - you might visit via std::visit().

C++ dynamic_cast a template class to another template

I am working with template class A<widget_type> and I want to know if it is possible to dynamic_cast<A<another_type>*>(A<widget_type>*).
Question: in the following code, A<B>* target2 = dynamic_cast<A<B>*>(&source); returns a null pointer. Is it possible to cast a template class into the same class but with another template?
Edit: I have to make a program where an array holds A<B*> objects, but A<B*> objects may come from A<C*> or A<D*>. I need to check at run-time if the A<B*> can be casted into the desired template class. I can't use strong-typing for that reason, since A<B*> object may come from an A<E*> object, where E is a class that other people may create and thus, there may not be a conversion function into that template class.
Code:
template<typename widget_type>
class A
{
public:
std::vector<widget_type*> value;
virtual ~A() {}
void Add(widget_type* val)
{
value.push_back(val);
}
template<typename return_type>
operator A<return_type>()
{
unsigned int size = this->value.size();
std::vector<return_type*> return_value;
return_value.resize(size);
for (unsigned int i = 0; i < size; i++)
{
return_value[i] = dynamic_cast<return_type*>(this->value[i]);
}
A<return_type> target;
target.value = return_value;
return target;
}
};
class B
{
public:
virtual ~B() {}
};
class C : public B
{
public:
void Print()
{
std::cout << "C CALL\n";
}
};
class D : public B
{
};
int main()
{
std::cout << "Start!\n";
A<C> source;
C* val1 = new C;
source.Add(val1);
A<B> target = source;
A<B>* target2 = dynamic_cast<A<B>*>(&source);
if (target2)
{
std::cout << "POINTER\n";
}
std::cout << "END\n";
}```
dynamic_cast will only succeed if there is some kind of inheritance relation between where you are coming from and where you are going to.
If you simply want to treat a pointer of one type as a pointer to a different type (which in general is true of different specializations of the same template) then dynamic_cast will not succeed. Only a c-style or reinterpret_cast will allow the cast but even then the results are not defined.

Mapping class types to other class types in C++

Given the following type hierarchy
class Base { public: virtual ~Base(); }
class OurDervied : public Base {}
class TheirDerived : public Base {}
class General { public: virtual ~General(); }
class MySpecial : public General {};
class YourSpecial : public General {};
I have a function f(Base *bp).
In f, I want to create an object with type that depends on the type passed in. For example, f creates a MySpecial when receiving an instance of OurDerived, and creates a YourSpecial when receiving an instance of TheirDerived.
I think I can do this with dynamic_cast. It probably requires trying to cast the received object repeatedly until a match is found (non-nullptr returned).
Another option is giving OurDerived, TheirDerived, etc a unique tag and then use a switch case construct to create MySpecial, YourSpecial, etc.
Are there any other options for mapping class types in C++?
Manual Type Switching
If the types you want to create have no common ancestor, you have no other option but use a
if (dynamic_cast<const DerivedA *>(&base))
{
// Create an object of some type.
}
else if (dynamic_cast<const DerivedB *>(&base))
{
// Create an object of some other type.
}
else if (dynamic_cast<const DerivedC *>(&base))
{
// Create an object of yet aother type.
}
else
{
// Handle the case that no type was matched. Maybe use a default or
// issue an error.
}
cascade and there is no direct way you can return the created object because a function cannot decide at run-time what return type it wants to have. The only way out would be to use type erasure or ugly unions.
Lookup Table with Factory Functions
Fortunately, this is not what you have to do if all the types you want to create are derived from a common base class, as you have indicated in the comments. In this case, you can map the typeid of an object to a factory function that creates the appropriate object. As usual with run-time polymorphism, this requires a heap allocation.
void
take_action(const Base& base)
{
using FactoryT = std::function<std::unique_ptr<General>()>;
static const std::map<std::type_index, FactoryT> factories {
{typeid(DerivedA), [](){ return std::make_unique<Special1>(); }},
{typeid(DerivedB), [](){ return std::make_unique<Special2>(); }},
{typeid(DerivedC), [](){ return std::make_unique<Special3>(); }},
};
const auto o_uptr = factories.at(typeid(base))();
// Use the object. It can also be returned.
}
I have made the std::map<std::type_index, std::function<FactoryT()>> static so it is created only once for the entire run-time of the program. It is not clear whether or not this is beneficial in your particular situation. Maybe benchmark it.
Here is a complete working example.
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <typeindex>
#include <typeinfo>
struct Base
{
virtual ~Base() = default;
virtual std::string
name() const
{
return "Base";
}
};
std::ostream&
operator<<(std::ostream& os, const Base& base)
{
return os << base.name();
}
template<char Token>
struct Derived : Base
{
virtual std::string
name() const override
{
std::string name {"Derived"};
name += Token;
return name;
}
};
using DerivedA = Derived<'A'>;
using DerivedB = Derived<'B'>;
using DerivedC = Derived<'C'>;
struct General
{
virtual ~General() = default;
virtual std::string
name() const
{
return "General";
}
};
template<char Token>
struct Special : General
{
virtual std::string
name() const override
{
std::string name {"Special"};
name += Token;
return name;
}
};
std::ostream&
operator<<(std::ostream& os, const General& general)
{
return os << general.name();
}
using Special1 = Special<'1'>;
using Special2 = Special<'2'>;
using Special3 = Special<'3'>;
void
take_action(const Base& base)
{
using FactoryT = std::function<std::unique_ptr<General>()>;
static const std::map<std::type_index, FactoryT> factories {
{typeid(DerivedA), [](){ return std::make_unique<Special1>(); }},
{typeid(DerivedB), [](){ return std::make_unique<Special2>(); }},
{typeid(DerivedC), [](){ return std::make_unique<Special3>(); }},
};
const auto o_uptr = factories.at(typeid(base))();
std::cout << base << " was mapped to " << *o_uptr << std::endl;
}
int
main()
{
take_action(DerivedA {});
take_action(DerivedB {});
take_action(DerivedC {});
return 0;
}
Output:
DerivedA was mapped to Special1
DerivedB was mapped to Special2
DerivedC was mapped to Special3
Visitor Pattern
Of course, you should ask yourself the question why you actually want to do this. There are for sure legitimate applications of this technique but taking an abstract type and then taking action based on its dynamic type is usually a sign of over-abstraction and makes for poorly maintainable code. Did you consider adding the factory directly to Base?
struct Base
{
virtual ~Base() = default;
virtual std::unique_ptr<General>
getDealer() = 0;
// ...
};
The Derived classes can then override getDealer to do what the factories lambdas did in the above example.
If this seems to intrusive (maybe the Base class shouldn't know anything about the General class at all), you could consider using the visitor pattern. It is a bit more work but allows for better decoupling. There is plenty of information available on this pattern so I'll only show its application to your specific problem and refer you to your favorite search engine if you need more explanation.
#include <iostream>
#include <memory>
#include <string>
struct BaseVisitor;
struct Base
{
virtual ~Base() = default;
virtual void
accept(BaseVisitor&) const = 0;
virtual std::string
name() const
{
return "Base";
}
};
std::ostream&
operator<<(std::ostream& os, const Base& base)
{
return os << base.name();
}
template<char Token>
struct Derived : Base
{
virtual void
accept(BaseVisitor& vtor) const override;
virtual std::string
name() const override
{
std::string name {"Derived"};
name += Token;
return name;
}
};
using DerivedA = Derived<'A'>;
using DerivedB = Derived<'B'>;
using DerivedC = Derived<'C'>;
struct BaseVisitor
{
virtual ~BaseVisitor() = default;
virtual void
visit(const DerivedA&) = 0;
virtual void
visit(const DerivedB&) = 0;
virtual void
visit(const DerivedC&) = 0;
};
// Cannot be defined earlier because we need the complete type of BaseVisitor.
template<char Token>
void
Derived<Token>::accept(BaseVisitor& vtor) const
{
vtor.visit(*this);
}
struct General
{
virtual ~General() = default;
virtual std::string
name() const
{
return "General";
}
};
template<char Token>
struct Special : General
{
virtual std::string
name() const override
{
std::string name {"Special"};
name += Token;
return name;
}
};
std::ostream&
operator<<(std::ostream& os, const General& general)
{
return os << general.name();
}
using Special1 = Special<'1'>;
using Special2 = Special<'2'>;
using Special3 = Special<'3'>;
void
take_action(const Base& base)
{
struct Mapper : BaseVisitor
{
std::unique_ptr<General> uptr {};
virtual void
visit(const DerivedA&) override
{
this->uptr.reset(new Special1 {});
}
virtual void
visit(const DerivedB&) override
{
this->uptr.reset(new Special2 {});
}
virtual void
visit(const DerivedC&) override
{
this->uptr.reset(new Special3 {});
}
};
Mapper visitor {};
base.accept(visitor);
std::cout << base << " was mapped to " << *visitor.uptr << std::endl;
}
int
main()
{
take_action(DerivedA {});
take_action(DerivedB {});
take_action(DerivedC {});
return 0;
}
Note how we have nicely broken the coupling between Base and General. On the down side, we had to introduce some kind of parent-to-child dependency via the BaseVisitor class.
This solution also gets completely rid of any explicit run-time type inference and elegantly lets the dynamic dispatch machinery do all the magic behind the scenes.
Yes, you can delegate type mapping to derived classes:
class Base
{
public:
virtual General* map() = 0;
};
class OurDerived: public Base
{
protected:
General* map()
{
// compute Type* for OurDerved
}
};
class TheirDerived: public Base
{
protected:
General* map()
{
// compute Type* for TheirDerived
}
};
It's hard to say without knowing what responsibilities your function has, or how you feel about coupling {My|Your}Special to {Our|Their}Derived.
Is Base constructible? Is Base or its derived classes allowed to have virtual methods? If you already incurred the cost of a vtable, I would delegate the responsibility to the derived types themselves, and explicitly make the method abstract on Base to force each derivation to explain itself in this regard.
Are MySpcial / YourSpecial related in the type hierarchy? Otherwise you are better off experimenting with explicit template instantiations of a helper function.

Is it possible to attach a name to a runtime class in C++?

I have an hierarchy of classes, the base class having a function to print the class name:
#include <iostream>
using namespace std;
class base
{
public:
virtual void print_name() { cout << typeid(*this).name() << endl; };
};
class derived1 : public base { };
class derived2 : public base { };
int main ()
{
base Base;
Base.print_name();
derived1 Derived1;
Derived1.print_name();
derived2 Derived2;
Derived2.print_name();
}
The output of the above is
class base
class derived1
class derived2
which is, in fact, platform dependent.
Is there a more or less standard way to "attach" some unique name to each class, so it could be used in printname() making the output the same for all platforms (and independent of any changes made to real class names)?
Sure:
class base {
public:
virtual char const *name() const { return "base"; }
};
class derived1 : public base {
public:
virtual char const *name() const { return "derived1"; }
};
However, if you do not override name in a class, its name will be that of its superclass. That may be a bug or a feature, depending on your use case. If it's a bug, then you can add some runtime checks to make sure the method is overridden:
virtual char const *name() const {
if (typeid(*this) != typeid(base))
throw std::logic_error("name() not overridden");
return "base";
}
But you'll have to repeat this check in every implementation of name that must be overridden.
You can effectively use type_info for this.
type_info supports a before method conforming to a Weak Order, which allows its use in a std::map (for example) as long as a user-supplied predicate is provided.
struct TypeInfoLess {
bool operator()(std::type_info const* lhs, std::type_info const* rhs) const {
return lhs->before(rhs);
}
};
struct AdditionalTypeInfo {
std::string name;
};
typedef std::map<std::type_info const*, AdditionalTypeInfo, TypeInfoLess> TypeInfoMap;
Then, you can just add/search types:
template <typename T>
void add(TypeInfoMap& map, T const& t, AdditionalTypeInfo const& ati) {
map[&typeid(t)] = ati;
}
template <typename T>
AdditionalTypeInfo const* find(TypeInfoMap const& map, T const& t) {
TypeInfoMap::const_iterator it = map.find(&typeid(t));
if (it == map.end()) { return 0; }
return &it->second;
}
int main() {
TypeInfoMap timap;
add(timap, timap, { "TypeInfoMap" });
if (AdditionalTypeInfo const* const ati = find(timap, timap)) {
std::cout << ati->name << "\n";
}
}
Note: it is then your responsability to add to the map every type that you might want.
You can use template functions (or traits classes) to get names:
template<typename T> const char * ClassName(T const * objPtr);
template<> const char * ClassName<derived1>(derived1 const *objPtr) { return "derived1"; }
template<> const char * ClassName<derived2>(derived2 const *objPtr) { return "derived2"; }
(Here the function parameter is used for template parameter matching only).
And in calling code you can cast your pointer to specific class and use ClassName
derived1 * pDerived = static_cast<derived1*>(pPointer);
cout << ClassName(pDerived);
However this is all compile-time, and you will need some mechanism (like GUIDs) to identify a class at runtime (to cast it to the right pointer type). If your classes have none and you can't modify them, than I can't help you;( But you can use traits technique to localize your platform-dependent type selection code.

Determining size of a polymorphic C++ class

Using the sizeof operator, I can determine the size of any type – but how can I dynamically determine the size of a polymorphic class at runtime?
For example, I have a pointer to an Animal, and I want to get the size of the actual object it points to, which will be different if it is a Cat or a Dog. Is there a simple way to do this, short of creating a virtual method Animal::size and overloading it to return the sizeof of each specific type?
If you know the set of possible types, you can use RTTI to find out the dynamic type by doing dynamic_cast. If you don't, the only way is through a virtual function.
Or you can use typeid, which might be faster than dynamic_cast (also with dynamic_cast you can cast to intermediary types in the hierarchy).
It looks rather bad:
#include <iostream>
#include <typeinfo>
class Creature
{
char x[4];
public:
virtual ~Creature() {}
};
class Animal: public Creature { char x[8];};
class Bird: public Creature { char x[16]; };
class Dog: public Animal { char x[32]; };
class Cat: public Animal { char x[64]; };
class Parrot: public Bird { char x[128]; };
unsigned creature_size(const Creature& cr)
{
if (typeid(cr) == typeid(Animal)) {
return sizeof (Animal);
}
else if (typeid(cr) == typeid(Dog)) {
return sizeof(Dog);
}
else if (typeid(cr) == typeid(Cat)) {
return sizeof(Cat);
}
else if (typeid(cr) == typeid(Bird)) {
return sizeof(Bird);
}
else if (typeid(cr) == typeid(Parrot)) {
return sizeof(Parrot);
}
else if (typeid(cr) == typeid(Creature)){
return sizeof(Creature);
}
assert(false && "creature_size not implemented for this type");
return 0;
}
int main()
{
std::cout << creature_size(Creature()) << '\n'
<< creature_size(Animal()) << '\n'
<< creature_size(Bird()) << '\n'
<< creature_size(Dog()) << '\n'
<< creature_size(Cat()) << '\n'
<< creature_size(Parrot()) << '\n' ;
}
For each new type you'll need to add code to the creature_size function. With a virtual size function you'll need to implement this function in each class as well. However, this function will be significantly simpler (perfectly copy-n-pasteable, which shows there might be both a limitation in the language and a problem with your code design):
virtual unsigned size() const { return sizeof(*this); }
And you can make it abstract in the base class which means that it will be a compiler error if you forget to override this method.
Edit: this is naturally assuming that given any Creature you want to know its size. If you have a strong reason to believe that you are dealing with a Dog - or a subclass of Dog (and you don't care if it is a subclass), then naturally you can use dynamic_cast for an ad hoc test.
If you are able to change source classes' design, you can totally replace dynamic polymorphism (which uses virtual functions) with static polymorphism and use the CRTP idiom:
template <class TDerived>
class Base
{
public:
int getSize()
{ return sizeof(TDerived); }
void print()
{
std::cout
<< static_cast<TDerived*>(this)->getSize()
<< std::endl;
}
int some_data;
};
class Derived : public Base<Derived>
{
public:
int some_other_data1;
int some_other_data2;
};
class AnotherDerived : public Base<AnotherDerived>
{
public:
int getSize()
{ return some_unusual_calculations(); }
// Note that the static_cast above is required for this override to work,
// because we are not using virtual functions
};
int main()
{
Derived d;
d.print();
AnotherDerived ad;
ad.print();
return 0;
}
You can do this when the needed polymorphic behavior of program can be determined at compile-time (like the sizeof case), since the CRTP has not the flexibility of dynamic polymorphism to resolve the desired object at run-time.
The static polymorphism also has the advantage of higher performance by removing virtual-function-call overhead.
If you don't want to templatize Base class or you need to hold different derived instances of Base class in a same location (like an array or a vector), you can use CRTP on a middle class and move the polymorphic behavior to that class (similar to the Polymorphic copy construction example in the Wikipedia):
class Base
{
public:
virtual int getSize() = 0;
void print()
{
std::cout << getSize() << std:endl;
}
int some_data;
};
template <class TDerived>
class BaseCRTP: public Base
{
public:
virtual int getSize()
{ return sizeof(TDerived); }
};
class Derived : public BaseCRTP<Derived>
{
// As before ...
};
class AnotherDerived : public BaseCRTP<AnotherDerived>
{
// As before ...
// Note that although no static_cast is used in print(),
// the getSize() override still works due to virtual function.
};
Base* obj_list1[100];
obj_list1[0] = new Derived();
obj_list1[2] = new AnotherDerived();
std::vector<Base*> obj_list2;
obj_list2.push_back(new Derived());
obj_list2.push_back(new AnotherDerived());
--
Update: I now found a similar but more detailed answer on stackoverflow which explains that if we further derive from the derived classes above (e.g. class FurtherDerived : public Derived {...}), the sizeof will not report correctly. He gives a more complex variant of the code to overcome this.
I can't believe that somebody's invented type_id() instead of implementing proper traits ....
One slightly convoluted way that will also work is to implement this through a Curiously Recurring Template Pattern
#include <iostream>
class Base {
public:
virtual ~Base() {}
virtual size_t getSize() = 0;
};
template <class T>
class BaseT : public Base {
public:
size_t getSize() override { return sizeof(T); }
};
class Child : public BaseT<Child> {};
int main()
{
std::unique_ptr<Base> child(new Child);
std::cout << child->getSize();
}