Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

std::vector i problem z dodawaniem elementów dziedziczących po klasach z fmetodami czysto wirtualnymi

Ostatnio zmodyfikowano 2012-05-02 17:08
Autor Wiadomość
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:


C/C++
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() );
P-55767
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.
P-55768
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().
P-55777
Admixior
» 2012-05-02 13:20:53
Mam pytanie. Jak wygląda definicja obj_list?
P-55779
Virpi
Temat założony przez niniejszego użytkownika
» 2012-05-02 13:35:20
C/C++
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 )
        {
            // dodaj slimaka
            obj_list.push_back( CSlimak() );
        }
    }
}

To kontener zawierający różne klasy, które dziedziczą po klasie bazowej CElement_gry.
P-55781
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 ;)
P-55783
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.
P-55785
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:
C/C++
std::vector < CElement_gry * > obj_list;
CElement_gry nowy = new[ i ] nazwa_klasy[ / i ];
//tutaj ustawienie odpowiednio danych
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.
P-55803
« 1 »
  Strona 1 z 1