2
votes

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();
            }
        }


}
2
You appear to be travelling along a bad path. If doSomething is a virtual member function of Shape, you can call doSomething without doing any gymnastics to determine the type. If doSomething is not a virtual member function of Shape, ask yourself "Why isn't it?"user4581301
This works as intended with doSomething as virtual function. Check this out.coliru.stacked-crooked.com/a/365df4bc103ee929. If it is not virtual, then the compilation itself will fail.P.W
@P.W using #include <bits/stdc++.h> isn't something we should be passing on. Plus using it means you don't need to include any of the other things you've included.user4581301
@user4581301: That was just for a quick demo for something in a comment. I won't be writing like that in any answer.P.W
@yosmo78 learning is a good answer to "Why isn't it?" I'm in the same boat as P.W. I can't reproduce any errors so long as Circle and Square are proper polymorphic inheritors of Shape: ideone.com/LU6mJo But without at least one virtual function in the base... It just won't work: ideone.com/mUYC84user4581301

2 Answers

2
votes

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
votes

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.