Search code examples
c++templatesdynamic-cast

Ambiguous conversion in dynamic_cast


Consider the problem of getting an object as argument and printing its type:

#include <iostream>

class A { };
class B : public A { };
class C : public A { };
class D : public C, public B { };

using namespace std;

template<class T>
void print_type(T* info)
{
    if(dynamic_cast<D*>(info))
        cout << "D" << endl;
    else if(dynamic_cast<C*> (info))
        cout << "C" << endl;
    else if(dynamic_cast<B*>(info))
        cout << "B" << endl;
    else if(dynamic_cast<A*> (info))
        cout << "A" << endl;
}

int main(int argc, char** argv)
{
    D d;
    print_type(&d);
    return 0;
}

It gives me the following error: "Ambiguous conversion from derived class 'D' to base class."
But I fail to see where's the ambiguity: if the object declared in main (d) is of type D, why can't be it directly converted to a type A?

Also, if I pass an argument of type string of course I get other errors:
'std::basic_string<char>' is not polymorphic

In Java for generics there is the syntax: <T extends A>; in this case it would be useful. How can I make a similar thing in C++ with templates?


I have modified the code this way:

#include <iostream>
#include <vector>

class A { };
class B : virtual public A { };
class C : virtual public A { };
class D : public C, public B { };

using namespace std;

template<class T>
void print_type(T* info)
{
    if(dynamic_cast<D*>(info))
        cout << "D" << endl;
    else if(dynamic_cast<C*> (info))
        cout << "C" << endl;
    else if(dynamic_cast<B*>(info))
        cout << "B" << endl;
    else if(dynamic_cast<A*> (info))
        cout << "A" << endl;
}

int main(int argc, char** argv)
{
    string str;
    print_type(&str);
    return 0;
}

But I still get the error: 'std::basic_string<char>' is not polymorphic


Solution

  • Consider the problem of getting an object as argument and printing it's type:

    Sigh... use RTTI.

    #include <iostream>
    #include <string>
    #include <typeinfo>
    
    template<class T> void print_type(const T& info){
        std::cout << typeid(info).name() << std::endl;
    }
    
    int main(int argc, char** argv){
        D d;
        int a = 3;
        std::string test("test");
        print_type(d);
        print_type(a);
        print_type(test);
        return 0;
    }