typeid.name() not changing when iterating through a vector. Dynamic cast and typeid a base class pointer

折月煮酒 提交于 2021-02-16 21:04:54

问题


Answer: In short use virtual functions! So don't actually use this as good design, but for learning purposes take a read!

I want to start off by saying I am using c++ and Qt I have a vector of Shape pointers (Base class)

Edit: doSomething() is not a member of the Base class but instead a derived class member. Which is why I am using dynamic_cast to get Shape* to the Derived* so that I can access it. I am really doing this just out of curiosity at this point though and for other peoples learning about c++'s type system

    #include <vector>
    using namespace std;
    vector<Shape *> vec;

Where I push back some derived classes of shape

    vec.push_back(new Square());
    vec.push_back(new Circle());

Ok then I get an iterator to the beginning

    vector<Shape *>::iterator tmp = vec.begin();

Here I want to iterate through the vectors

    for(;tmp != vec.end(); ++tmp)
    {
        if(typeid(**tmp).name() == typeid(Square).name())
        {
            Square * sptr = dynamic_cast<Square *>(*tmp);
            sptr->doSomething();
        }
        else if(typeid(**tmp).name() == typeid(Circle).name())
        {
            Circle * cptr = dynamic_cast<Circle *>(*tmp);
            cptr->doSomething();
        }
    }

However Both result in the Square output; not the circle for the second. I tried comparing the memory locations of typeid

Like so:

    &typeid(**tmp) == &typeid(Square)

and the same for circle but tmp always results in the square for the case above and when ran against the circle right afterwards... Is dynamic cast doing something with the vector as a whole of am I just missing something with how typeid() works?

Edit: Here is the answer, thanks to user4581301 (I also added some thing too!):

#include <iostream>
#include <vector>
#include <typeinfo>

struct Shape
{
    virtual ~Shape(){} //Something here must be virtual or pure virtual!
};

struct Circle: Shape
{
    void doSomething(){std::cout << "Circle" << std::endl;}
};
struct Square: Shape
{
    void doSomething(){std::cout << "Square" << std::endl;}
};

int main()
{
    std::vector<Shape *> vec;
    vec.push_back(new Square());
    vec.push_back(new Circle());
    std::vector<Shape *>::iterator tmp = vec.begin();

        for(;tmp != vec.end(); ++tmp)
        {
            if(&typeid(**tmp) == &typeid(Square))
            {
                Square * sptr = dynamic_cast<Square *>(*tmp);
                sptr->doSomething();
            }
            else if(&typeid(**tmp) == &typeid(Circle))
            {
                Circle * cptr = dynamic_cast<Circle *>(*tmp);
                cptr->doSomething();
            }
        }


}

回答1:


This works as intended with doSomething as a virtual function. If it is not virtual, then the compilation itself will fail (if there are no other functions in the Shape class which are virtual). Dynamic cast will fail if source type is not polymorphic.

If it is virtual, you need not do what you are doing to determine the type. Let polymorphism do its magic. You can shorten your code like this:

#include <iostream>
#include <vector>

class Shape { public: virtual void doSomething() {std::cout << "In Shape\n";}};
class Circle: public Shape {public: void doSomething() {std::cout << "In Circle\n";}};
class Square: public Shape {public: void doSomething() {std::cout << "In Square\n";}};

int main() {
    std::vector<Shape *> vec;
    vec.push_back(new Square);
    vec.push_back(new Circle);

    for(auto tmp = vec.begin();tmp != vec.end(); ++tmp)
    {       
        (*tmp)->doSomething();        
    }
}



回答2:


For dynamic cast to work, any of the function in base class must be virtual, that mean base class must be used in polymorphic way.



来源:https://stackoverflow.com/questions/53531927/typeid-name-not-changing-when-iterating-through-a-vector-dynamic-cast-and-typ

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!