Dziedziczenie klas i wywoływanie funkcji z klas pochodnych

2013-01-12 13:50

Rejestracja: 7 lat temu

Ostatnio: 6 lat temu

0

Mam klasę bazową i z niej dziedziczą 2 klasy pochodne, które mają metody odziedziczone po klasie bazowej + swoje własne.

Tworzę listę obiektów klasy bazowej:

void Plansza::dodaj_na_liste(Pionek *obiekt)
{
    lista_Pionkow.push_back(obiekt);
}

a później wywołuję takie coś:

lista_Pionkow[j]->set_zdrowie(....); 

Nie chce się kompilować, ponieważ klasa bazowa nie zawiera czegoś takiego jak set_zdrowie, ale zawiera to klasa pochodna. Jak w takim razie to rozwiązać? W klasie bazowej powinny być wszystkie możliwe metody? Czy jakoś inaczej to wpisać, żeby wiedział, że chodzi mi o obiekt klasy pochodnej? Czy jeszcze może coś nie tak z tworzeniem listy?

edytowany 1x, ostatnio: Mruvek, 2013-01-12 13:53

Pozostało 580 znaków

2013-01-12 15:36

Rejestracja: 17 lat temu

Ostatnio: 1 rok temu

Lokalizacja: Katowice

1

Czy chciałeś tutaj wykorzystać polimorfizm? Jeżeli tak to nie zrobisz tego w ten sposób, interfejs klasy bazowej musi być ustalony i muszą go implementować wszystkie klasy pochodne - jeżeli dodają coś do tego interfejsu to nie będzie tego można wykonać posiadając jedynie wskaźnik na klasę bazową. Istnieje operator dynamic_cast który umożliwia zrobienie czegoś takiego, ale potrzeba jego wykorzystania często oznacza, że program jest po prostu źle zaprojektowany.

Jaki jest Twój projekt klas i co zamierzasz osiągnąć?


"(...) otherwise, the behavior is undefined".
edytowany 1x, ostatnio: Endrju, 2013-01-12 15:36

Pozostało 580 znaków

2013-01-12 18:12

Rejestracja: 7 lat temu

Ostatnio: 6 lat temu

0

Tak, chciałem skorzystać z polimorfizmu. Do czasu przeczytania Twojej odpowiedzi zrobiłem tak jak myślałem wcześniej czyli dodałem do klasy bazowej wszystkie metody. Czytałem też o dynamic_cast, ale jakoś nie pasowało mi jego użycie. Oczywiście, że pewnie całość klas jest źle zaprojektowana, bo robię to pierwszy raz i nie wiem jak powinno wyglądać i "jak to się ogólnie robi" :P Wszystko wygląda tak:

class Pionek
{
protected:
    int pozycja;        // pozycja na planszy
    string nazwa;
public:
    Pionek();
    void set_pozycja(int n);
    int get_pozycja();
    virtual void set_start() = 0;
    void przesun(int ile);
    virtual void set_nazwa();
    string get_nazwa();

    void set_zdrowie(int);
    int get_zdrowie();
    int get_sila();
    int get_zasieg();
}; 
 class Pionek_gracza : public Pionek
{
private:
    int zdrowie;
public:
    Pionek_gracza(int nrp);
    int get_zdrowie();
    void set_zdrowie(int n);
    void set_start();
};
class Pionek_potwora : public Pionek
{
private:
    int sila;
    int zasieg;
public:
    Pionek_potwora(int nsila, int nzasieg, int i);
    int get_sila();
    int get_zasieg();
    void set_start();
};

Posiadam listę pionków, czy raczej wskaźników na pionki stworzoną tak:

void Plansza::tworz_pionki() // tworzy wszystkie pionki i nadaje im nazwy
{
    for(int i=0; i<3; i++) 
    {
        dodaj_na_liste(new Pionek_gracza(i+1));
        lista_Pionkow[i]->set_nazwa();
    }

    for(int i=0;i<4;i++)
    {
        dodaj_na_liste(new Pionek_potwora(10,10,i));
        lista_Pionkow[i]->set_nazwa();
    }
}

Co chcę osiągnąć:
wywołując takie coś

lista_Pionkow[j]->set_zdrowie(....); 

chcę żeby przestawiło mi zdrowie pionka_gracza na podaną wartość. Metoda set_zdrowie w klasie Pionek jest pusta, w klasie Pionek_potwora nie ma jej wcale (potwory nie mają zdrowia), jest tylko w klasie Pionek_gracza.
Wyrzuca błędy takie:
błąd:undefined reference toPionek::get_zdrowie()'- i jeszcze podobnych 4, wszystkie mają ten sam problem, najwyżej z inną metodą. :-1: błąd:collect2: ld returned 1 exit status `

Wszystko to działało, dopóki miałem 2 tablice osobne dla potworów i graczy. Problemem jest tylko to, że teraz mam jedną listę ze wskaźnikami na Pionek (klasę bazową)

edytowany 1x, ostatnio: Mruvek, 2013-01-12 18:14

Pozostało 580 znaków

2013-01-12 20:21

Rejestracja: 14 lat temu

Ostatnio: 1 dzień temu

0

A gdzie masz zdefiniowaną metodę Pionek::get_zdrowie(), widzę samą deklaracje.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.

Pozostało 580 znaków

2013-01-12 20:34

Rejestracja: 7 lat temu

Ostatnio: 6 lat temu

0

W pliku źródłowym klasy Pionek

int get_zdrowie() {return -1;}
edytowany 1x, ostatnio: Mruvek, 2013-01-12 20:39

Pozostało 580 znaków

2013-01-12 21:49

Rejestracja: 14 lat temu

Ostatnio: 1 dzień temu

0

A dołączyłeś plik źródlowy klasy pionek do projektu?


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.

Pozostało 580 znaków

2013-01-12 21:53

Rejestracja: 7 lat temu

Ostatnio: 6 lat temu

0
SOURCES += main.cpp \
    plansza.cpp \
    pionek_gracza.cpp \
    pionek_potwora.cpp \
    kostka.cpp \
    Pionek.cpp

HEADERS += \
    plansza.h \
    pionek_gracza.h \
    pionek_potwora.h \
    kostka.h \
    Pionek.h

Według mnie tak : )

Pozostało 580 znaków

2013-01-12 21:56

Rejestracja: 14 lat temu

Ostatnio: 1 dzień temu

0

masz tak:
int get_zdrowie() {return -1;}
czy tak:
int Pionek::get_zdrowie() {return -1;}
?


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.

Pozostało 580 znaków

2013-01-12 21:59

Rejestracja: 17 lat temu

Ostatnio: 1 rok temu

Lokalizacja: Katowice

0

To akurat może być wina projektu - dodałeś do niego wszystkie pliki? Poza tym jak słusznie napisał @_13th_Dragon ta definicja wygląda źle.

Co do projektu to jest on trochę dziwny. Czy polimorfizm jest Ci niezbędny? Proste rozwiązania są dobre - zawrzyj to co wspólne w klasie Pionek i wyprowadź z niej te dwie klasy różnych pionków, które będą dodawać swoje funkcjonalności. Trzymaj to w dwóch tablicach jak poprzednio i nie korzystaj z polimorfizmu, co było w tym złego?

Jeżeli uprzesz się na polimorfizm będziesz mieć interfejs, który klasy pochodne będą musiały niepotrzebnie implementować, bo jak mówisz część funkcjonalności nie jest wspólna. Można w zasadzie wykorzystać do tego "domyślne" wersje funkcji z klasy bazowej, ale moim zdaniem taki projekt nie jest za dobry.


"(...) otherwise, the behavior is undefined".
edytowany 1x, ostatnio: Endrju, 2013-01-12 21:59

Pozostało 580 znaków

2013-01-12 22:51

Rejestracja: 7 lat temu

Ostatnio: 6 lat temu

0

Fakt, nie dodałem Pionek:: ...

Tak jak Endrju mówisz miałem od początku w głowie, tak działa, jest okej dla tego projektu i już. Jednak prowadzący chciał polimorfizmu, żeby zamiast 2 tablic była lista wspólna - oczywiście to w ramach tego żebyśmy uczyli się jakiś wzorców projektowych może, żeby rozszerzyć i 'zuniwersalnić' kod mimo że w tym projekcie to może nie jest potrzebne. Pewnie trzeba było mieć inny pomysł, coś inaczej zaplanować, albo w ogóle wszystko inaczej itd. Ja to powiedzmy rozumiem, ale mam inne przedmioty, to ma konkretny termin i muszę skończyć chociaż trochę robiąc po jego myśli.

Pozostało 580 znaków

2013-01-12 22:57

Rejestracja: 14 lat temu

Ostatnio: 1 dzień temu

0

Albo czegoś nie zrozumiałeś albo wasz wykładowca nie zna się na wzorcach projektowych. Jak słusznie zauważył @Endrju - tego tak się nie robi - a mówią o tym głośnie i wyraźnie wzorce projektowe.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.

Pozostało 580 znaków

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0