Questions about Polymorphism

I'm so confused.. :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Base{
    
protected:
    string username;
    string name;
    
public:
    
    //Constructors
    Base(){
        username = "Base";
        name = "";
    }
    
    //Virtual Members

    virtual void printInfo() const{
        cout<<"Base"<<endl<<endl;
    }    
    
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Derived : public Base{
    
private:
    
    //string username; INHERITED
    //string name;     INHERITED
    string surname;
    string date;
    
public:
    
    //CONSTRUCTORS
    Derived();
    Derived(const string &username, const string &name, const string &surname, const string &date);
    void printInfo() const override{
        cout<<"Derived";
    }
    
};


1
2
3
4
5
6
7
8
9
10
int main(int argc, const char * argv[]) {
    vector<Base> vect1;
    vect1.push_back(Derived());
    vect1[0].printInfo();
    
    vector<shared_ptr<Base>> vect2;
    vect2.push_back(make_shared<Derived>(Derived()));
    vect2[0]->printInfo();

}


Why in the first vector I see "base" while in the second "derived"? .. I know that the "shared_ptr" and "unique_ptr" allow you to create a vector that uses polymorphism, but why? What happens at the compiler?

Is there other way to make a vector that use polymorphism?

Last edited on
closed account (SECMoG1T)
i hope this will help you understand.

One of the key features of class inheritance is that a pointer to a derived class is 
type-compatible with a pointer to its base class. Polymorphism is the art of taking advantage
of this simple but powerful and versatile feature.


cplusplus ref:
http://www.cplusplus.com/doc/tutorial/polymorphism/
Last edited on
But i know that... i mean, why if i remove "shared_ptr" i can't use polymorphism?.. what this "shared_ptr" do on this vector?
A vector<Base> stores objects of type Base, nothing else. If you try to insert a Derived object into such a vector only the Base part of the object will be copied and stored inside the vector.
closed account (SECMoG1T)
it is not necessary a shared_ptr but any base class pointer/reference can be used to point to an object derived from the base class, that is because a derived class pointer can be implicitly converted to a base class pointer, without the need for dynamic cast
1
2
3
4
5
6
7
struct Base {
  char foo;
};

struct Derived : public Base {
  char bar;
}

Lets assume that one Base object uses one byte of memory. Therefore,
Base fubar[10];
fubar requires 10 bytes.

The Derived object needs at least two bytes (for foo and bar).
Ten Derived objects need thus 20 bytes. You cannot fit 10 Derived into fubar.

Base* snafu[10]; requires 10 * sizeof(Base*) bytes.
snafu contains pointers. A pointer that can point to Base object could point to a Derived object too. That will not change the size of the pointer.
The snafu has ten pointers, regardless of whether those pointers point to somewhere or not.

Same applies to shared_ptr objects. Their change remains same no matter where they point to.


This is object slicing:
1
2
vector<Base> vect1;
vect1.push_back( Derived() );

Similar, but much more verbose:
1
2
3
4
5
6
7
Derived temp;
temp.foo = 'a';
temp.bar = 'b';
Base gaz;
gaz.foo = temp.foo;
vector<Base> vect1;
vect1.push_back( gaz );

You did create unnamed temporary Derived. I did create 'temp'.
The vector::push_back takes a Base object as parameter. I had 'gaz' as additional step.
Only the 'a' in Base::foo is stored into the vector.
Last edited on
@vittorioc98

In your OP, the first part of the code in the main function (lines 2 to 4)shows how it doesn't work. Because it has the slicing which keskiverto explains.

Lines 6 to 8 shows how it does work. Because it pushes a pointer of Derived into a container which expects a pointer to Base, which is OK as mentioned by Yolandaand shown again by me, below. It need not be a shared pointer, a normal pointer is OK too.

The example in the OP is not a good one because it only puts 1 thing into the container. It's more demonstrative if there are several different types in the container.

http://www.cplusplus.com/doc/tutorial/polymorphism/

And this posted by Yolanda earlier, emphasis by me:

One of the key features of class inheritance is that a pointer to a derived class is
type-compatible with a pointer to its base class. Polymorphism is the art of taking advantage
of this simple but powerful and versatile feature.


One way of looking at this a container of Shape : std::vector<Shape*> AllTheShapes;

Shape is the base class with a pure virtual area function, the derived classes might be triangle, regularpolygon, circle etc. They all have their own version of the area member function.

Now we fill this vector with pointers to the derived class objects. The compiler calls the correct derived area function because it has a pointer to the derived class object, but it needs to check as described in the next paragraph.

Because it is a container of Base class pointers, only base class functions can be called. But this is OK because the derived classes have their own version of the function in the base class. This is known as the interface - that is, the public functions in the base class a user can call to interact with all the derived class objects.


Next iterate through all the items in the vector, and call the area function. The compiler does the right thing


This is a really big advantage:

* We write std::vector<Base*> , we do not have:

std::vector<Triangle> Triangles;
std::vector<regularpolygon> Regularpolygons;
std::vector<circle> Circles;

and having to add more of these if we add another type of Shape, and change all the code everywhere so it works with the new type.

When we use Polymorphism, we can can add a new type Shape like class ellipse : public Shape {}; all we have to do is define an area function for it, and all the other code still works.

So we can have a lot less number of containers, and a lot less numbers of functions.

This also demonstrates how naming is important. We have a function in each derived class, all with the same name - area. We don't have TriangleArea, CircleArea etc.

I was looking for an example of code online, but all the examples I found had aspects I didn't like. Hopefully my explanation is sufficient :+)

Topic archived. No new replies allowed.