jeżeli nie chcesz zajmować się tgo typu problemami, zainsteresuj się np. boost::serialization
a jeżeli chcesz, to Twoj pierwszy program nie ma szansy działac poprawnie, bez napisanego prawidłowo i bardzo szczegółowo operatora >> (istream, Obiekt*).
problem w tym, że probujesz używac "polimorfizmu" na opak
AAA) w C++ polimorfizm dziala tylko "na lewą stronę", czyli mając linijkę:
wskNaObiektA -> wirtualnametoda (be)
jedynym "polimorficznym" zachowaniem jest wywolanie NA obiektA jednej z wielu wersji jego wirtualnejmetody, w zaleznosci od jego faktycznego typu (nie typu zmiennej wskNaObiektA, tylko typu obiektuA na ktory ona wskazuje), tzn. jesli obiektA bedzie Żyjątkiem, Wielokomorkowcem, Zwierzeciem, Ssakiem, Naczelnym, czy Czlowiekiem, to wywola sie "metoda" ustalona przez tę właśnie klasę, zakladająć "naturalne" dziedziczenia pomiedzy nimi..
istotne jest tu, że NIE JEST ISTOTNE czym FAKTYCZNIE jest BE.
jeżeli BE jest "obiekt*", to nie wazne czy jest ono Psem, Kotem, Domem, czy Osobą, uzywa zostanie sygnatura "wirtualnametoda(Obiekt*)" - tyle że dynamicznie wzieta z "wlasciwej klasy wg. obiektuA"
to znaczy, że jeżeli chcesz operowac na Dom albo Mieszkanie poprzez Obiekt*, to NIE MASZ (sensownej) szansy na użycie polimorfizmu między nimi, jeżeli Twoja linijka wygląda tak:
cos -> bum (obiektdomlubmieszkanie)
a jedynie moglbys probowac, jesli wyglada tak:
obiektdomlubmieszkanie -> bum (cos)
natychmiast neutralizuje to probę użycia strumien>>zmiennatypuobiekt* i zmusza Cie do napisania jakiejs wirtualnej metody "wczytaj" w domie lub mieszkaniu i wywolywanie:
domlubmieszkanie -> wczytaj ( strumien )
to jest "podstawa", w ten sposob i Dom i Mieszkanie beda mialy wlasne kody wczytywania, i w ten sposob wlasciwe wczytywanie "samo sie" odpali.
a jak to sobie teraz "ładnie opakujesz", to Twoja sprawa. Mozesz np. opakowac to w operator >> na strumieniu:
operator >> (strumien, obiekt* ob)
ob -> wczytaj (strumien)
i juz! od tej pory kazde wywolanie >> na strumieniu, z podaniem jakiegos domlubmieszkanie, samo sobie wybierze wlasciwe "wczytaj", zgodnie z faktyczna klasa "ob"
BBB) istnieje jeszcze druga metoda - korzystanie z "statycznego polimorfizmu". W zasadzie, czemu masz w jednej metodzie rozpoznawac typ obiektu i go przygotowywac, a pozniej w drugiej sie glowic co to za obiekt byl i odpalac wlasciwa metode? Skoro pierwsza wykryla ze jest to DOM, niech odpali czytanie DOMu natychmiast, i tak dalej. W tym momencie, przygotowujesz sobie kod wczytywania poszczegolnych typow obiektow i kod "rozpoznawania obiektu" z:
czy dom? -> return new Dom;
czy mieszkanie -> return new Mieszkanie;
zamieniasz na:
czy dom? -> zrób nowe Dom; wczytaj Dom ze strumienia; return ów Dom
czy mieszkanie -> zrób nowe Mieszkanie; wczytaj mieszkanie ze strumienia; return owo Mieszkanie
i ponownie, jak to teraz sobie "ubierzesz", tak się wyspisz..
mozesz na przyklad uznac, ze Dom/Mieszkanie powinny miec takie konstruktory:
public:
Dom (strumien & ) { wczytywanie ze strumienia...
i wtedy:
czy dom? -> zrób nowe Dom(strumien);
czy mieszkanie -> zrób nowe Mieszkanie(strumien);
ale, mozesz tez chciec miec konstruktory "puste" i uzywac operatorow >> !
czy dom? -> DOM * = zrób nowe Dom(); cin >> *ówdom ; return ówdom
czy tez nawet globalnych funkcji:
czy dom? -> DOM * = zrób nowe Dom(); wczytaj(cin, ówdom) ; return ówdom
i czegokolwiek innego, BYLEBY "ówdom" miało typ zmiennej DOKLADNIE taki sam jak tworzonego obiektu - czyli Dom*, Mieszkanie*, Pies*, a nie "ogólne" Obiekt*.
w skrocie:
- polimorfizm i funkcje wirtualne wymagają, aby "polimorficzność" stala po lewej stronie. metoda "do dopasowania" ma byc NA polimorficznym czyms wykonana
- "statyczny polimorfizm" opiera sie na przeciązeniach i rozpatrywaniu podczas kompilacji. wymaga, aby typy zmiennych byly sztywne, konkretne i dokladne.
ciekawostka:
polimorfizm zwykly "lewostronny" mozesz tez sprytnie rozszerzac na "wiecej stron" poprzez użycie .. statycznego polimorfizmu. Ogólnie chodzi o DoubleDispatch widziany często w "implementacjach wzorca Visitor", i sprowadza się to do napisanie kilku (a czasem bardzo bardzo wielu) metodek pomocniczych, "odbijających piłeczkę" pomiędzy klasami "zbierających po drodze" informację kto-kim-jest:
KlasaA
wirtualna zrobCos( obiektX ) { obiektX->zrobCos(this)
KlasaB : KlasaA
wirtualna zrobCos( obiektX ) { obiektX->zrobCos(this)
KlasaC : KlasaA
wirtualna zrobCos( obiektX ) { obiektX->zrobCos(this)
KlasaD : KlasaA
wirtualna zrobCos( obiektX ) { obiektX->zrobCos(this)
wywolujac np. wskaNaKlasaA->zrobCos, w efekcie wywolanie zostanie odbite do obiektuX, ale dzieki wirtualności "zrobCos" oraz dzieki pieczolowitemu przepisaniu tej metodki wszedzie owo "THIS" będzie statycznie wiedziało, że jest typu KlasaD. jeżeli teraz ObiektX będzie miał:
KlasaX
wirtualna zrobCos( KlasaA ob) { ....
wirtualna zrobCos( KlasaB ob) { ....
wirtualna zrobCos( KlasaC ob) { ....
wirtualna zrobCos( KlasaD ob) { .... <- to wywola się to
wirtualna zrobCos( Klasa... ob) { ....
KlasaY : KlasaX
wirtualna zrobCos( KlasaA ob) { ....
wirtualna zrobCos( KlasaB ob) { ....
wirtualna zrobCos( KlasaC ob) { ....
wirtualna zrobCos( KlasaD ob) { .... <- lub to, zaleznie czy obiektX FAKTYCZNIE byl Xem czy Ykiem..
wirtualna zrobCos( Klasa... ob) { ....
czyli majac takie "krzyzowe" konstrukcje "szeroko" rozpisane, uzyskujesz, że wywolujac wskaNaKlasaA->zrobCos( wskaNaKlasaX ) to pomimo jedynie "lewostronnego polimorfizmu", w efekcie wywoła się wersja zrobCos dokladnie wiedząca że chodzi o KlasaD<->KlasaY..
tak wiec "bawic sie" mozna.. ale czy tego potrzebujesz? ocen sam