2015-04-27 2 views
0

Как вы можете видеть, в обоих случаях вызывается только перегруженная версия оператора вставки потока для базового класса. Я понимаю, почему это так. Это связано с тем, что динамическая привязка отсутствует. Но как я могу это исправить?Оператор потоковой передачи и перегрузки

#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; 
} 

Как я могу сделать cout << *(array[1]); вызов перегруженной поток вставки оператора, который принимает объект B, как один из его аргументов?

+0

Прочитайте это: [«Что такое срез объектов?»] (Https://stackoverflow.com/questions/274626/what-is-object-slicing). Затем посмотрите, как вы '' 'массив страдает от того, что описано в вопросе и ответах. – WhozCraig

+0

@WhozCraig Не будет нарезки, объекты передаются по ссылке. – phantom

+0

@Phantom посмотрите на объявление 'array'. Вы не можете иметь массивы родных ссылок. Это простой массив из 'A'. Инициализатор с использованием 'b' (' array [1] ') нарезается. – WhozCraig

ответ

2

Вы можете определить вспомогательные функции виртуального члена.

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; 
} 

Вам не нужно даже 2 operator<<() «S больше.

Для operator >> (istream& in, A& a) аналогичные трюки могут быть выполнены.

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; 
} 
+0

Каково решение в качестве функции друга? – User2k14

+0

Если вы настаиваете на том, чтобы не добавлять виртуальные функции-члены, вы можете объявить деструкторы как виртуальные и использовать 'dynamic_cast', чтобы проверить, прошел ли' A & 'в действительности' B & '. – timrau

+0

Ох ... это выглядит немного неуклюжим. Как раз для полноты, можете ли вы показать, как применить предыдущее решение, которое вы отправили в оператор извлечения потока (>>)? – User2k14

0

Если A знает, что это будет наследоваться от, вы можете использовать Non Virtual Interface: сделать друг операторов, и написать защищенного (это не входит в интерфейсе класса) виртуальной функции, которая выполняет запись.

Смежные вопросы