3

Class DVD inherits class Media, has one more variable than the base class does.

I declare a pointer:

Media* ptr = new DVD(...);

I want to print out the content of the DVD, so the following code works as expected:

ptr->print(cout);

But using the overloaded << operator only invokes the base class print() function:

cout << *ptr << endl;

So it prints out only the ID, not with the name of the director.

One way to solve this problem is to modify the overload << operator a bit to make it accept pointers, so:

cout << ptr << endl;

should work, but somehow I must find the way to make cout << *ptr << endl; work as expected.

Any advice?

The thing is I can't make the base class (Media) abstract because I need to call an instance of it in the overloading ostream operator, so a pointer of the base class can not invoke the overloading function of the derived class, which it's pointing to.

Code:

#include <iostream>
using namespace std;

class Media{
    private:
        int id;
    public:
        Media(int _id) : id(_id) {}
        virtual ~Media();
        virtual void print(ostream &out);
        friend ostream& operator << (ostream& out, Media aMedia);
};
Media::~Media(){}

class DVD : public Media {
    private:
        string director;
    public:
        DVD(int _id, string _director = "unknown") : Media(_id), director(_director) {}
        ~DVD();
        void print(ostream &out);
};
DVD::~DVD(){}

void Media::print(ostream& out){
    out << "ID " << id;
}
void DVD::print(ostream& out){
    out << "DVD: ";
    Media::print(out);
    out << " Directed by " << director;
}
ostream& operator << (ostream& out, Media aMedia){
    aMedia.print(out);
    return out;
}

int main() { 
    Media *ptr = new DVD(352, "Stephen Spielberg"); 
    ptr->print(cout); // Prints out: "DVD: ID 352 Directed by Stephen Spielberg". Correct!
    cout << endl; 
    cout << *ptr << endl; //Prints out: "ID 352" Incorrect!
} 
Max
  • 3,824
  • 8
  • 41
  • 62

2 Answers2

1

Or pass aMedia by reference Media& to << so that virtual dispatching will occur.

You're passing a Media object directly, which means a new copy of the DVD object will be created, and the DVD only parts will be thrown away and just the Media parts of it will be end up in the aMedia parameter.

see:

ostream& operator << (ostream& out, const Media& aMedia){
    aMedia.print(out);
    return out;
}
Scott Langham
  • 58,735
  • 39
  • 131
  • 204
  • 1
    Better make it a const reference. – Henrik Apr 05 '12 at 10:18
  • All good, I had never understood clearly why should we use const reference in overloading functions rather than just use the variable itself, but all clear now. Thanks! – Max Apr 05 '12 at 10:24
1

Problem is in this declaration ostream& operator << (ostream& out, Media aMedia). You are accepting the parameter aMedia by copy which causes object slicing, accept it by using a reference by changing the signature to ostream& operator << (ostream& out, const Media& aMedia) .

Because of the slice when you do cout << *ptr , a copy of the DVD is created of type Media (i.e. DVD is sliced to a Media), now when you call print since the type of the object is Media call goes to the Media::print. You can read more about object slicing here.

Community
  • 1
  • 1
Naveen
  • 74,600
  • 47
  • 176
  • 233
  • All good, I had never understood clearly why should we use const reference in overloading functions rather than just use the variable itself, but all clear now. Thanks! – Max Apr 05 '12 at 10:30