Virpi Temat założony przez niniejszego użytkownika |
std::vector i problem z dodawaniem elementów dziedziczących po klasach z fmetodami czysto wirtualnymi » 2012-05-01 23:54:41 Witam, pisząc swoją grę chciałem użyć kontenera, jakim jest vector, jednak mam problem podczas dodawania do niego obiektow klas, które dziedziczą po klasach posiadających metody czysto wirtualne. Jeśli natomiast metoda move() będzie metodą po prostu wirtualną, to wszystko jest w porządku. Czy jest to specyfika tego kontenera, że nie da się tak zrobić? Zamieszczam ważniejsze fragmenty kodu:
class CElement_gry { public: CElement_gry(); virtual ~CElement_gry(); virtual void move() = 0; };
class CElement_sterowalny : public CElement_gry { public: CElement_sterowalny(); virtual ~CElement_sterowalny(); virtual void move() = 0; };
class CSlimak : public CElement_sterowalny { public: CSlimak(); virtual ~CSlimak(); void move(); protected: private: };
class CAkwarium { public: CAkwarium(); virtual ~CAkwarium(); std::vector < CElement_gry > obj_list; };
obj_list.push_back( CSlimak() );
|
|
akwes |
» 2012-05-02 01:05:37 Problem czyli? Coś się nie kompiluje/coś nie działa(co konkretnie)?
Jeżeli chodzi o to, że coś się nie chce dodać do vektora to dlatego że jest innego typu. Tutaj musisz wykorzystać wskaźniki najprawdopodobniej. Bo tablica CSlimak i CObiektSterowalny maja różne rozmiary, zaś wskaźniki rozmiary mają te same, i możliwość utworzenia tablicy jest tylko w drugim przypadku.
Zobacz sobie, że tablica musi być ciągiem obiektów o tym samym rozmiarze (operator sizeof( obiekt ), powie ile wazy obiekt). Więc trzeba zrobić tablicę wskaźników i potem rzutować ewentualnie. |
|
Virpi Temat założony przez niniejszego użytkownika |
» 2012-05-02 12:45:04 Błąd pojawia się taki:
error: cannot allocate an object of abstract type 'CElement_gry'
a jeśli metoda czysto wirtualna będzie tylko w klasie CElement_sterowalny, to kompiluje się bez problemu.
Poza tym jest OK, tak mi się wydaje, przecież wykorzystując polimorfizm za pomocą wskaźnika CElement_gry* mogę stworzyć obiekt klasy CSlimak, bo klasa ta dziedziczy po CElement_sterowalny, a ta po CElement_gry. Dziwi mnie to, dlaczego wyrzyca mi błąd, że nie może stworzyć obiektu klasy abstrakcyjnej, przecież nie tworzę obiektu tej klasy, tylko innej dziedziczącej po niej, w której ta metoda move() jest zastąpiona przez zwykłą metodę void move(). |
|
Admixior |
» 2012-05-02 13:20:53 Mam pytanie. Jak wygląda definicja obj_list? |
|
Virpi Temat założony przez niniejszego użytkownika |
» 2012-05-02 13:35:20 std::vector < CElement_gry > obj_list;
void CAkwarium::add_item( sf::Event key ) { if( key.Type == sf::Event::KeyReleased ) { if( key.Key.Code == sf::Key::A ) { obj_list.push_back( CSlimak() ); } } }
To kontener zawierający różne klasy, które dziedziczą po klasie bazowej CElement_gry. |
|
waxx |
» 2012-05-02 13:41:03 Nie możesz tak, bo klasy dziedziczące mogą mieć inny rozmiar niż typ bazowy. Wrzucaj do kontenera wksaźniki, a będzie ok ;) |
|
Virpi Temat założony przez niniejszego użytkownika |
» 2012-05-02 13:58:20 ok, ale jeśli nie wykorzystam metod czysto wirtualnych, to do tego kontenera mogę wrzucić i ślimaka i inne pochodne klasy... kompiluje się bez problemu. |
|
Admixior |
» 2012-05-02 17:08:27 Jeśli masz metodę czysto wirtualną to nie możesz definiować takich obiektów. Po drugie std::vector < CElement_gry > obj_list; to jest wiadomo co. A klasa która ma metodę czysto wirtualną nie może istnieć. W symfonii było to wytłumaczone. Wysyłając element do funkcji przez wartość tak jak to tutaj robiłeś funkcją push_back() kopiuje się sama zawartość klasy CElement_gry. Pozostałość się traci. Czyli już nigdy nie odzyskasz to co było obok CElement_gry, mniej więcej wygląda to tak: kilka_bajtów CElement_gry | kilka_bajtów rzeczy których dorzuciłeś w dziedziczeniu | pozostałe śmieci gdy dodasz do wektorów przez push_back (kopiowanie danych) wygląda tak: kilka_bajtów CElement_gry | pozostałe śmieci Więc cała informacja że kiedyś ... była inna klasa - przepadły. A więc skoro jest tylko CElement_gry to można powiedzieć że to była definicja klasy z funkcją wirtualną. Stąd błąd. Nie ma rady musisz użyć wskaźnika. mniej więcej tak: std::vector < CElement_gry * > obj_list; CElement_gry nowy = new[ i ] nazwa_klasy[ / i ];
i dodanie metoda push_back()
później musisz przed destruktorem wektora zrobić pętlę i usuwać każdy element tego wektora przez delete, a wirtualny destruktor załatwi pozostałe rzeczy. Gdybyś kiedyś chciał korzystać z elementów które ma tylko dana klasa co dziedziczy CElement_gry - poczytaj na temat dynamic_cast. |
|
« 1 » |