Lazar Lazarov
Lazar Lazarov

Reputation: 33

C++ - Object slicing even after using pointers

I have a base class Shape, and a derived class Circle which inherits Shape publically:

class Circle : public Shape

I made a C++ vector of Shape pointers, and I assigned Circle pointers to them. I'd read up a lot on object slicing so expected the code to treat the Circle in the vector as a Circle, not a Shape.

Can anyone point out what's wrong with this, given the output?

int main(void) {
vector<Shape*> shapes;

Circle* ncl = new Circle(-8, -8, 0.2f);
shapes.push_back(ncl);

cout << "Expected: " << *ncl << endl;
cout << "Reality: " << *shapes[0] << endl;
}

outputs:

Expected: Circle is at: -8,-8 and has a radius of: 0.2
Reality: Shape centered at point: -8,-8

I have overridden the << operator for both classes out of scope, so I think that's not the problem, but still - here's the code context of my overrides:

inline std::ostream& operator<< (std::ostream& stream, const Shape& shape) {
    std::cout << "Shape centered at point: " << shape.getX() << "," << shape.getY();
    return stream;
}

inline std::ostream& operator<< (std::ostream& stream, const Circle& circle) {
    std::cout << "Circle is at: " << circle.getX() << "," << circle.getY() << 
        " and has a radius of: " << circle.getR();
    return stream;
}

All in all - I want to be able to access my Circle variables properly while they're stored in the Shape vector (with pointers or otherwise).

Upvotes: 2

Views: 785

Answers (2)

molbdnilo
molbdnilo

Reputation: 66431

There's no slicing involved, it just looks like it.

Overloads are selected at compile time, from the static type as it is known to the compiler.
Since shapes is a vector<Shape*>, *shapes[0] is a Shape&, and that overload is chosen.

The common solution is to only write an operator<< for the base class, and that in turn calls a virtual function on the object.
This will let the dynamic function dispatch select the function at runtime.

For instance:

struct Shape  { virtual ostream& print(ostream& os) const { ... } };
struct Circle { ostream& print(ostream& os) const override { ... } };

ostream& operator<<(ostream& os, const Shape& s) { return s.print(os); }

Upvotes: 3

Jarod42
Jarod42

Reputation: 217593

overload resolution is done with static type.

You may use:

std::ostream& operator<< (std::ostream& stream, const Shape& shape) {
    shape.print(stream);
    return stream;
}

with virtual void Shape::print(std::ostream&) const; to solve your issue.

Upvotes: 1

Related Questions