7

Possible Duplicate:
Virtual Functions Object Slicing

let's consider:

#include <vector>
#include <iostream>
using namespace std;

struct A {
    virtual void do_it() { cout << "A" << endl; } 
};

struct B : public A {
    virtual void do_it()  { cout << "B" << endl; } 
};

int main() {
    vector<A> v;
    v.push_back(B());
    v[0].do_it(); // output is A
}

which function will be called? Basically is it possible to use polymorphism without pointers if no slicing is present?

Community
  • 1
  • 1
lezebulon
  • 7,607
  • 11
  • 42
  • 73
  • 2
    "if no slicing is present" is the key point. You are slicing. So what do you expect? – PlasmaHH Jul 26 '12 at 14:01
  • The problem is that there is slicing in your example. So, it will not work. – betabandido Jul 26 '12 at 14:03
  • When the object is copied into the vector. – betabandido Jul 26 '12 at 14:03
  • @lezebulon You must be very careful with hacks like these. In this case, it will _probably_ be OK in most implementations, but take the case where class A doesn't have virtual functions and class B does. Then class B often (probabbly depending on implementation) needs more storage per object! – Mr Lister Jul 26 '12 at 14:08
  • @lezebulon: The slicing comes from converting the `B` to `A` when inserting it in the vector, losing the information that it was created from a `B`. `v[0]` has type `A`, and so the last line calls `A::do()`. – Mike Seymour Jul 26 '12 at 14:13

5 Answers5

15

No it will not be possible without pointers.

Since you create an object B and push it to the vector containing A, it will get copied (sent to the copy constructor of A) and an instance of A will be added to the vector. I.e. the object will be sliced.

Given this code:

struct A {
        virtual void d() { 
            std::cout << "Hello A" << std::endl; 
        } 
};

struct B : public A {
        virtual void d() { 
            std::cout << "Hello B" << std::endl; 
        } 
};

int main() {
        std::vector<A> v;
        v.push_back(B());
        v[0].d();
}

The output will be:

Hello A
Man of One Way
  • 3,904
  • 1
  • 26
  • 41
6

The problem is that in your example there is actually slicing. Using push_back is somehow equivalent to:

A array[N];
array[last++] = B();

In the second line is where you have the slicing, since each position in the array can hold an object from type A but not one from type B.

You could use pointers to solve this problem, defining v as std::vector<A*> v. Probably better, you could use smart pointers (either the ones present in C++11 or the ones in Boost).

betabandido
  • 18,946
  • 11
  • 62
  • 76
5

Does polymorphism work in C++ without pointers / references?

Yes and no.

Dynamic polymorphism works in C++ when the static type of a pointer or reference might be different to the dynamic type of the object it refers to, and behaviour is chosen based on the dynamic type. This requires pointers or references, since the object itself has only one type.

Static polymorphism, using templates, works perfectly with objects, but solves a different class of problem. Your example requires dynamic polymorphism, to choose behaviour based on the run-time type of the objects.

which function will be called?

The vector contains objects of type A, so A::do_it() will be called. The object has no knowledge that it was created by slicing an object of type B.

Basically is it possible to use polymorphism without pointers if no slicing is present?

Slicing is always present when you create base-class objects from derived-class objects. That is the definition of slicing.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
4

Does polymorphism work in C++ without pointers / references?

Yes. See static polymorphism.

In your case, the base function will be called, but saying polymorphism doesn't work is wrong. Polymorphism is guaranteed to work, it's just that you're not taking advantage of it. What you have is basically a collection of A objects.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
0

This will not work, since sizeof(parent) will not always equal sizeof(child)

Nico
  • 3,826
  • 1
  • 21
  • 31
  • this will work, but probably not as expected. – moooeeeep Jul 26 '12 at 14:13
  • It has nothing to do with the size. The vector stores A's by copying from the parameter, so it will copy the A part of a B. – Bo Persson Jul 26 '12 at 14:17
  • It has nothing to do with object sizes. It will "work" in the sense that an `A` will be placed in the vector, initialised from a temporary `B`; it won't exhibit the polymorphism that the OP seems to be hoping for. – Mike Seymour Jul 26 '12 at 14:17
  • It won't exhibit polymorphism because the sizeof( A* ) will not always equal sizeof( B* ) due to the virtual function table offset. Since that portion of B will not be copied it does not work. – Nico Jul 26 '12 at 16:03