User2k14
User2k14

Reputation: 69

Upcasting and Overloading Stream Operator

As you can see, only the overloaded version of the stream insertion operator for the base class is called on both instances. I understand why it's so. It's because there is no dynamic binding. But, how do I fix it?

#include <iostream>

using namespace std;

class A {
    int i;
    char c;
public:
    A(int i = 0, char c = ' ') {
        this->i = i;
        this->c = c;
    }
    int getI() { return i; }
    char getC() { return c; }
    friend ostream& operator << (ostream&, A&);
};

class B : public A {
    double d;
public:
    B(int i = 0, char c = ' ', double d = 0.0) : A(i, c), d(d) {}
    friend ostream& operator << (ostream&, B&);
};

ostream& operator << (ostream& out, A& a) {
    out << "\nInteger: " << a.i << "\nCharacter: " << a.c << endl;
    return out;
}

ostream& operator << (ostream& out, B& b) {
    out << "\nInteger: " << b.getI() << "\nCharacter: " << b.getC() << "\nDouble: " << b.d << endl;
    return out;
}

int main() {
    A* a = new A (10, 'x');
    B* b = new B(20, 'y', 5.23);
    A* array[] = { a, b };
    cout << *(array[0]);
    cout << "\n______________________________\n";
    cout << *(array[1]);
    delete a;
    delete b;
    cin.get();
    return 0;
}

How can I make cout << *(array[1]); call the overloaded stream insertion operator that takes an object of B as one of it's arguments?

Upvotes: 0

Views: 164

Answers (2)

timrau
timrau

Reputation: 23058

You can define virtual member helper functions.

class A {
public:
    virtual void toStream(ostream& out) const {
        out << "\nInteger: " << i << "\nCharacter: " << c << endl;
    }
};

class B : public A {
public:
    virtual void toStream(ostream& out) const {
        out << "\nInteger: " << getI() << "\nCharacter: " << getC() << "\nDouble: " << d << endl;
    }
};

ostream& operator << (ostream& out, const A& a) {
    a.toStream(out);
    return out;
}

You don't even need 2 operator<<()'s anymore.

For operator >> (istream& in, A& a), similar tricks could be done.

class A {
public:
    virtual void fromStream(istream& in) {
        // Fill data members with in
    }
};

class B : public A {
public:
    virtual void fromStream(istream& in) {
        // Fill data members with in
    }
};

istream& operator >> (istream& in, A& a) {
    a.fromStream(in);
    return in;
}

Upvotes: 2

Ekleog
Ekleog

Reputation: 1054

If A knows it will be inherited from, you can use Non Virtual Interface: make the operators friend, and write a protected (it's not part of the class interface) virtual function that performs the write.

Upvotes: 0

Related Questions