latajacaryba Temat założony przez niniejszego użytkownika |
» 2017-08-18 23:01:58 @mokrowski Ja rozumiem działanie polimorfizmu. Zauważ tylko, że klasa "drzwi" dziedziczy po klasie pole, więc jeśli mam referencje/wskaźnik do zwykłego pola oraz do drzwi i gracz chce wejść w interakcję z drzwiami, to muszę wywołać metodę: A TO oznacza, że w klasie Pole musi być metoda wirtualna "interakcja". To może jeszcze działać, ale co, jeśli mam w klasie "Drzwi" stan drzwi - bool SaOtwarte ? Z poziomu wskaźnika do klasy Pole nie moge się do tego dostać... PolePtr = & Drzwi; bool CzyDrzwiSaOtwarte = PolePtr->SaOtwarte;
Więc jak mogę odwoływać się do składników klasy pochodnej, mając wskaźnik klasy podstawowej? Jak to załatwić? |
|
jankowalski25 |
» 2017-08-18 23:45:18 |
|
latajacaryba Temat założony przez niniejszego użytkownika |
» 2017-08-19 00:21:18 Też o tym myślałem, jednak nie zawsze wiadomo, czy to są drzwi, fontanna lecznicza czy co innego. Mam taki pomysł: InterakcyjnePole dziedziczy po Pole. Klasa pole ma metode bool CzyInterakcyjne. Jeśli zwróci true, robię konwersję w dół (Pole na InterakcyjnePole) i wywołuje Interakcja :) Dzięki |
|
mokrowski |
» 2017-08-19 01:33:51 @latajacaryba, to dobrze że rozumiesz polimorfizm. Stąd będziesz wiedział że wystarczy zaimplementować metodę wirtualną zwracającą znacznik "kim jest klasa" i na tej podstawie zróżnicujesz wywołania lub zastosować inną metodę która będzie działała podobnie... Tak czy siak łamiesz taką detekcją regułę Liskov https://pl.wikipedia.org/wiki/Zasada_podstawienia_Liskov Nie sądzisz że Drzwi nie są rodzajem Pola? Oględnie mówiąc mają inne rodzaje interakcji więc inne interfejsy. #include <iostream> #include <vector>
class Drzwi; class Krzaczor;
struct Pole { virtual int kto() const = 0; virtual void interakcja( Pole * ) = 0; virtual void interakcja( Drzwi * ) = 0; virtual void interakcja( Krzaczor * ) = 0; virtual ~Pole() { } };
struct Drzwi : Pole { Drzwi() : otwarte { false } { } int kto() const override { return 1; } void interakcja( Drzwi * ) override { std::cout << "Drzwi\n"; } void interakcja( Krzaczor * ) override { } void interakcja( Pole * pole ) override { pole->interakcja( this ); } bool czyOtwarte() const { return otwarte; } void otwarcie() { otwarte = true; } void zamkniecie() { otwarte = false; } private: bool otwarte; };
struct Krzaczor : Pole { int kto() const override { return 2; } void interakcja( Krzaczor * ) override { std::cout << "Krzaczor\n"; } void interakcja( Drzwi * ) override { } void interakcja( Pole * pole ) override { pole->interakcja( this ); } };
struct Akcja { void akcjaPrzezId( Pole * pole ) { if( pole->kto() == 1 ) { std::cout << "Drzwi...\n"; } else if( pole->kto() == 2 ) { std::cout << "Krzaczor...\n"; } } virtual void akcja( Drzwi * drzwi ) { std::cout << "Drzwi\n"; } virtual void akcja( Krzaczor * krzaczor ) { std::cout << "Krzaczor\n"; } };
int main() { Akcja * a = new Akcja(); std::vector < Pole *> rzeczy; for( auto i = 0U; i < 5; ++i ) { rzeczy.push_back( new Krzaczor() ); } for( auto i = 0U; i < 3; ++i ) { rzeczy.push_back( new Drzwi() ); } std::cout << "Przez ID\n"; for( auto & rzecz: rzeczy ) { a->akcjaPrzezId( rzecz ); } std::cout << "Przez polimorfizm \n"; for( auto & rzecz: rzeczy ) { rzecz->interakcja( rzecz ); } for( auto & p: rzeczy ) { delete p; } delete a; }
|
|
latajacaryba Temat założony przez niniejszego użytkownika |
» 2017-08-19 02:25:40 No właśnie podświadomie wiem, ze coś jest nie tak, że musi być metoda mówiąca, czym jest obiekt ją wywołujący. Drzwi zdecydowałem się umieścić jako pochodną klasy pole, gdyż wszystkie pola/struktury chce trzymać w dwuwymiarowej tablicy wskaźników do obiektów pole. Nie mam pojęcia jak to inaczej załatwić :/ Chcę, by mając wskaźnik program sprawdzał, czy z polem da się wykonać interakcję. Jeśli tak, to ją wykonuje.
|
|
michal11 |
» 2017-08-19 09:50:42 Zrób kilka tablic i niech każdy obiekt w grze rejestruje się do tego co go interesuje ( rendering, kolizje, fizyka itp.), dodatkowo możesz poczytać o delegatach (tak to się chyba tłumaczy na polski) i o wzorcu obserwator. |
|
latajacaryba Temat założony przez niniejszego użytkownika |
» 2017-08-19 14:23:00 Cholera, muszę pomyśleć nad rozwiązaniem. To co mówisz byłoby całkiem Ok, tylko czasami interakcja jak otwieranie drzwi, czyli bez argumentów, innym razem leczenie gracza, czyli argument Player & , więc musiałbym mieć do każdego rodzaju struktury osobną tablicę... Muszę to rozwiązać tak, by łatwo było to zapisywać i wczytywać z pliku, także najwygodniejsza byłaby jedna tablica, ewentualnie kilka. Ale nie będę robił tablicy która będzie przechowywała milion elementow/wskaźników dla dwóch struktur typu fontanna życia. Ma to wyglądać jak okrojona Terraria. W założeniu. Może ktoś wpadnie na jeszcze jakiś pomysł, temat na razie zostawiam otwarty. PS. Czytałem o delegatach, oraz wzorcu obserwator, ale tu nie znajdą raczej zastosowania, szczególnie to drugie. |
|
michal11 |
» 2017-08-19 14:50:24 Kolizja (interakcja) zawsze ma stałą, określoną liczbę argumentów, kto koliduje, z kim koliduje + ew. jakaś struktura trzymająca dane z kontekstem kolizji (np. dokładna lokacja kolizji). Możesz mieć jedna główną tablicę ktora będzie faktycznie trzymała twoje obiekty (owning pointer) i pomocnicze tablice które będą miały tylko weak pointery, tych pomocniczych nie musisz zapisywać bo każdy obiekt w konstruktorze albo jakiejś funkcji inicjującej będzie się rejestrował do odpowiedniej tablicy. Podpowiedz z delegatami i obserwatorem można wykorzystać tak, że nie rejestrujesz obiektu tylko funkcję, dzięki temu nie musisz robić specjalnego interfejsu dla klasy bazowej, wystarczy tylko aby jakaś metoda miała odpowiednią sygnaturę. |
|
1 2 « 3 » 4 |