Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Перегрузка оператора вывода <<


Автор: gabin 14.10.2011, 23:41
Здравствуйте. Хочу сделать перегрузку оператора вывода <<. 
Иерархия классов: (абстрактный)Component -> Engine -> GasEngine.
Если я объявляю статический объект класса GasEngine, то вывод работает без проблем:
Код

GasEngine mazdaEngine(2092.22,"Инжектор",553);
cout<<mazdaEngine;
Результат:
Код

Тип двигателя : Инжектор
Стоимость двигателя : 2092.22
Вес двигателя : 553

Но если я объявляю объект как указатель на абстрактный класс Component , то тут начинаются проблемы.
Код

Component* bmwEngine = new GasEngine(30133.1,"Инжектор",667);
cout<<bmwEngine;

Результат:
Код

0x9cd0008

Как сделать корректной перегрузку оператора вывода в данном случае?

Исходный код проекта, сделанного в Eclipse, прикрепляю.

Автор: sQu1rr 14.10.2011, 23:57
Если оператор << перегружен для класса Component, то
Код

cout << *bmwEngine;


Добавлено через 1 минуту и 43 секунды
Соответственно, если нет, то что-то типо
Код

cout << dynamic_cast<GasEngine>(bmwEngine);

Автор: gabin 15.10.2011, 00:26
Цитата(sQu1rr @ 14.10.2011,  23:57)
Если оператор << перегружен для класса Component, то
Код

cout << *bmwEngine;


Добавлено @ 23:59
Соответственно, если нет, то что-то типо
Код

cout << dynamic_cast<GasEngine>(bmwEngine);


Оператор << перегружен для класса Engine и GasEngine.
1-й вариант не проходит, падает при выполнении:
Код

В функции ‘int main()’:
../src/Lab.cpp:39:9: ошибка: no match for ‘operator<<’ in ‘std::cout << * bmwEngine’
/usr/include/c++/4.5/ostream:108:7: замечание: претенденты: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:117:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type& (*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>, std::basic_ostream<_CharT, _Traits>::__ios_type = std::basic_ios<char>]
/usr/include/c++/4.5/ostream:127:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:165:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:169:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:173:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/bits/ostream.tcc:91:5: замечание:              std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.5/ostream:180:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/bits/ostream.tcc:105:5: замечание:              std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.5/ostream:191:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:200:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:204:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:209:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:213:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:221:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:225:7: замечание:              std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/bits/ostream.tcc:119:5: замечание:              std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__streambuf_type*) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>]
make: *** [src/Lab.o] Ошибка 1


2-й вариант с dynamic_cast при компиляции ошибка: 
Код

cannot dynamic_cast ‘bmwEngine’ (of type ‘class Component*’) to type ‘class GasEngine’ (target is not pointer or reference)

А вариант 
Код

cout<<dynamic_cast<GasEngine*>(bmwEngine);

Выводит что-то типа 0x9089008.

Автор: volatile 15.10.2011, 00:38
Цитата(sQu1rr @  14.10.2011,  23:57 Найти цитируемый пост)
cout << dynamic_cast<GasEngine>(bmwEngine);

Не так работать вообще не будет. Вы здесь указатель пытаетесь привести к самому объекту, это абсурд.

Цитата(sQu1rr @  14.10.2011,  23:57 Найти цитируемый пост)
cout << *bmwEngine;

А так не будет виртуализации.
Чтобы заработала виртуализация, надо оператор вывода объявлять не для объекта, а для ссылки на объект.
Тогда будет все нормально


Автор: mes 15.10.2011, 00:38
http://liveworkspace.org/code/1484f5e5f03347b2007f6756f5231fcb

Добавлено через 44 секунды
Код

#include <iostream>

struct IBase
{
   virtual void cout (std::ostream& o) const =0;
};

struct A : IBase 
{
   void cout (std::ostream& o) const
   {
       o << "classA ";
   }
};

struct B : IBase 
{
   void cout (std::ostream& o) const
   {
       o << "classB ";
   }
};

struct C : IBase 
{
   void cout (std::ostream& o) const
   {
       o << "classC ";
   }
};

std::ostream& operator << (std::ostream& o, const IBase& base)
{
   base.cout(o);
   return o;
}


int main ()
{
  IBase * a = new A ;
  IBase * b = new B;
  IBase * c = new C;
  
  std::cout << *c << *a << *b;
  
}

Автор: sQu1rr 15.10.2011, 11:31
Цитата(volatile @  15.10.2011,  00:38 Найти цитируемый пост)
Не так работать вообще не будет. Вы здесь указатель пытаетесь привести к самому объекту, это абсурд.

Я и не говорил что будет, я сказал что-то типо этого. Понятно, что указатель нужно привести к указателю smile

Автор: gabin 15.10.2011, 22:47
Цитата(mes)

http://liveworkspace.org/code/1484f5e5f033...07f6756f5231fcb


http://liveworkspace.org/code/b7a74e931da8bdf337089a4519e27ff3
Сделал по аналогии с вашим примером но теперь в методе класса не работает cout: 
 
Код

source.cpp: In member function 'virtual void Engine::printData()':
source.cpp:65:10: error: invalid use of member (did you forget the '&' ?)
source.cpp:66:10: error: invalid use of member (did you forget the '&' ?)

Build finished with errors

Автор: volatile 15.10.2011, 23:27
Цитата(gabin @  15.10.2011,  22:47 Найти цитируемый пост)
теперь в методе класса не работает cout:

уберите лишнее, и все заработает
http://liveworkspace.org/code/6b056ba78f64a09efdb34c799df835e3

Автор: volatile 15.10.2011, 23:45
Или, если вам нужна именно printData(), то так http://liveworkspace.org/code/6c8dfbc7604ad23c93d344af77d82951

А вообще идея называть методы именем cout - не очень хорошая идея.

Автор: gabin 15.10.2011, 23:59
Цитата(volatile @ 15.10.2011,  23:27)
Цитата(gabin @  15.10.2011,  22:47 Найти цитируемый пост)
теперь в методе класса не работает cout:

уберите лишнее, и все заработает
http://liveworkspace.org/code/6b056ba78f64a09efdb34c799df835e3

Спасибо. 


Автор: mes 16.10.2011, 10:17
Цитата(volatile @  15.10.2011,  22:45 Найти цитируемый пост)
А вообще идея называть методы именем cout - не очень хорошая идея.

особенно для тех кто любит :
Цитата

using namespace std;

Автор: gabin 16.10.2011, 19:54
В ходе дальнейшего расширения кода возникла проблема: реализовал шаблонный класс, который выполняет функции контейнера.
При добавлении в него POD объектов, контейнер работает без проблем - выводит через оператор << всё содержимое.
Но при добавлении полиморфных объектов базового абстрактного класса он опять выводит адреса. 
Странно, ведь в main() они успешно выводятся(да и оператор << перегружен), а вот в контейнере не хотят...
Вот код - http://liveworkspace.org/code/a4b8d24245e04091124d0091fa4b323f
Подскажите пожалуйста как разрешить эту проблему

Автор: mes 16.10.2011, 20:00
Цитата(gabin @  16.10.2011,  18:54 Найти цитируемый пост)
Подскажите пожалуйста как разрешить эту проблему 

разыменовывайте указатель.. 

Автор: gabin 16.10.2011, 20:56
Цитата(mes @ 16.10.2011,  20:00)
Цитата(gabin @  16.10.2011,  18:54 Найти цитируемый пост)
Подскажите пожалуйста как разрешить эту проблему 

разыменовывайте указатель..

Успешно, но теперь http://liveworkspace.org/code/91380229bfdd37f906b5c97143bd8cdeс POD объектами.
Получается, что шаблонный класс не универсален? И нужно реализовывать 2 шаблонных класса - для статических и для динамических объектов?

Автор: mes 16.10.2011, 22:00
Цитата(gabin @  16.10.2011,  19:56 Найти цитируемый пост)
Получается, что шаблонный класс не универсален? 

Вы просто не умеете их готовить © smile

чтоб заработал, можно например так (на скорую руку):
http://liveworkspace.org/code/1d3aa15e998361e57ce8579b462fa603



Автор: gabin 16.10.2011, 22:30
Цитата(mes @  16.10.2011,  22:00 Найти цитируемый пост)
Вы просто не умеете их готовить © smile

чтоб заработал, можно например так (на скорую руку):
http://liveworkspace.org/code/1d3aa15e9983...ce8579b462fa603

Гениально и просто !

Автор: mes 16.10.2011, 23:25
Цитата

Код

void storeToString(char*& aString)


а зачем тут ссылка на указатель то ? вы ж его не собираетесь переадресовывать..

Автор: gabin 17.10.2011, 09:54
Цитата(mes @  16.10.2011,  23:25 Найти цитируемый пост)
а зачем тут ссылка на указатель то ? вы ж его не собираетесь переадресовывать..

Спасибо. Поправил на 
Код

void storeToString(char* aString);

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)