#include <iostream>
#include <string>
#include <map>
#include <type_traits>
 
#define DEFINE_BASES(class, ...)                                                \
    static const std::string& GetClassNameStatic()                              \
    {                                                                           \
        static std::string className(#class);                                   \
        return className;                                                       \
    }                                                                           \
                                                                                \
    const std::string& GetClassName() const                                     \
    {                                                                           \
        return GetClassNameStatic();                                            \
    }                                                                           \
                                                                                \
    template <typename _empty>                                                  \
    void RegisterAllSubclasses() const                                          \
    {                                                                           \
                                                                                \
    }                                                                           \
                                                                                \
    template <typename _empty, typename T, typename... Args>                    \
    void RegisterAllSubclasses() const                                          \
    {                                                                           \
        T::RegisterAllSubclasses();                                             \
        RegisterAllSubclasses<void, Args...>();                                 \
    }                                                                           \
                                                                                \
    virtual void RegisterAllSubclasses() const                                  \
    {                                                                           \
        RegisterSubclass(static_cast<const void*>(this), class::GetClassName());\
        RegisterAllSubclasses<void, __VA_ARGS__>();                             \
    }
 
class Object
{
    public:
        virtual ~Object() { }
    
        static std::string& GetClassNameStatic()
        {
            static std::string className("Object");
            return className;
        }
 
        virtual const std::string& GetClassName() const
        {
            return GetClassNameStatic();
        }
 
        void* To(const std::string& className) 
        {
            if (_bases.size() == 0)
            {
                RegisterAllSubclasses();
            }
 
            auto result = _bases.find(className);
            return (result != _bases.end() ? (*result).second : NULL);
        }
 
        const void* To(const std::string& className) const
        {
            if (_bases.size() == 0)
            {
                RegisterAllSubclasses();
            }
 
            auto result = _bases.find(className);
            return (result != _bases.end() ? (*result).second : NULL);
        }
 
    protected:
        void RegisterSubclass(const void* ptr, const std::string& className) const
        {
            _bases[className] = const_cast<void*>(ptr);
        }
 
        virtual void RegisterAllSubclasses() const
        {
            RegisterSubclass(static_cast<const void*>(this), Object::GetClassName());
        }
 
    private:
        mutable std::map<std::string, void*> _bases;
};
 
////////////////////////////////////////////////////////////////////////////////
  
template <typename T>
T my_dynamic_cast(Object* ptr)
{
    return static_cast<T>(ptr->To(std::remove_pointer<T>::type::GetClassNameStatic()));
}
 
template <typename T>
T my_dynamic_cast(const Object* ptr)
{
    return static_cast<T>(ptr->To(std::remove_pointer<T>::type::GetClassNameStatic()));
}
  
////////////////////////////////////////////////////////////////////////////////
  
class InputStream : virtual public Object
{
    public:
        DEFINE_BASES(InputStream, Object);
        void Read() { }
};
  
class OutputStream : virtual public Object
{
    public:
        DEFINE_BASES(OutputStream, Object);
        void Write() { }
};
  
class IOStream : public InputStream, public OutputStream
{
    int _value;
 
    public:
        DEFINE_BASES(IOStream, InputStream, OutputStream);
        IOStream() : _value(0) { }
 
        int GetValue() const { return _value; }
        void SetValue(int value) { _value = value; }
};
  
int main()
{
    const Object*   co = new IOStream;
    const IOStream* cd = my_dynamic_cast<const IOStream*>(co);
     
    Object*   o = new IOStream;
    IOStream* d = my_dynamic_cast<IOStream*>(o);
 
    d->SetValue(42);
     
    printf("const:     %i, %p, %p\n", cd->GetValue(), co, cd);
    printf("non-const: %i, %p, %p\n", d->GetValue(), o, d);
     
    delete cd;
    delete d;
 
    return 0;
}