Autor Wątek: C++ wskaźnik na obiekt - nie wywołuje metod ani pól klasy pochodnej  (Przeczytany 1356 razy)

Offline FireBoll8

  • Użytkownik

# Czerwiec 23, 2010, 16:24:53
Witam przejdę odrazu do problemu :

otóż mam zdeklarowaną przykładową klasę Potwora :

class cMonster
{
public:
int HP;
const static int HP_MAX = 60;
int damage;
int armor;
int Sila;
// konstruktory
cMonster(){damage = 10, armor = 20, Sila = 15;}
// destruktor
virtual ~cMonster(){};
// metody
int Random();
};
// jej implementacja zawarta jest w main.cpp

Stworzyłem do niej także klase pochodną :

class cWolf: public cMonster
{
public:
int Ryk();
cWolf(){damage = 20,armor=22,Sila=20;}
};
I teraz chcąc odwołać się do klasy pochodnej stworzyłem wskaźnik na obiekt klasy bazowej cMonster i przypisałem do niego obiekt cWolf.
W ten sposób:
// wskaźnik na obiekt  klasy cMonster
cMonster *monster = new cWolf;
Gdy sprawdzam wartość zmiennych w programie np. armor, damage itp .. to zgadzają się , jednak gdy chcę odwołać się do metody przykładowej w tym wypadku Ryk(); Nie mogę tego uczynić z nieznanych mi powodów ...

Czy ktoś mógł by uświadomić mi moje błędy?

// Odpowiedź do poniżej żeby nie zaśmiecać - dzięki nie przerobiłem jeszcze rzutowania z klasami ale się za nie właśnie zabieram;]
Dziękuję za pomoc
« Ostatnia zmiana: Czerwiec 23, 2010, 16:29:02 wysłana przez FireBoll8 »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Kuba D.

  • Użytkownik

# Czerwiec 23, 2010, 16:27:07
Hint: popatrz na typ wskaźnika.
keyword: rzutowatnie

Offline Ivian

  • Użytkownik
    • Ivian's Cave

# Czerwiec 23, 2010, 16:36:53
zadeklaruj w klasie podstawowej
Kod: (cpp) [Zaznacz]
virtual int Ryk() = 0;
i dzięki polimorfizmowi będzie gitara.

@edit: rzutowanie też załatwi sprawę.


tip: używaj albo angielskiego albo polskiego w kodzie.
tip2: staraj się ukrywać zmienne pod specyfikatorem protected/private
« Ostatnia zmiana: Czerwiec 23, 2010, 16:39:12 wysłana przez Ivian »

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Czerwiec 23, 2010, 17:13:01
tip3: Całkowicie olej mechanizm dziedziczenia w tym zastosowaniu. Jeśli planujesz wiele rodzajów potworów znacznie lepiej zrobić całość na dwóch klasach: potwora (opisuje konkratną istotę) i definicji potwora (opisuje charakterystyki całego gatunku). W ten sposób kodu będzie mało, a w przyszłości będziesz mógł zrobić definiowanie potworów w wygodny sposób przez pliki konfiguracyjne.

Offline Xion

  • Redaktor
    • xion.log

# Czerwiec 23, 2010, 18:17:41
tip4: Nie postuj tutaj, jeśli chcesz konkretnych informacji. W najlepszym razie dostaniesz rady dobre, ale nie odpowiadające na pytanie (vide #3), a w gorszym - jakieś zagadkowe wskazówki.

Przyczyną błędów u ciebie jest to, że klasa bazowa cMonster nie ma metody Ryk(). Jeśli używasz wskaźnika typu cMonster*, to wszystkie metody, jakie chcesz za jego pośrednictwem wywołać, muszą być w owej klasie zdefiniowane (choćby jako (czysto) wirtualne). Nie ma tutaj znaczenia, że wskaźnik ten pokazuje na obiekt klasy pochodnej; może ma to sens z punktu widzenia działającego programu, ale kompilator nie może wiedzieć, na co ty wskaźnikiem będziesz pokazywać.

Offline Xirdus

  • Moderator

# Czerwiec 23, 2010, 19:56:32
Żeby zobrazować problem dam ci przykład: masz tą klasę CMonster i dziedziczące po niej CWolf i CWasp. CWolf ma metodę Ryk(), a CWasp ma metodę Bzyk(). Tworzysz wskaźnik klasy CMonster *Monster, który zależnie od sytuacji jest obiektem CWolf lub CWasp. W momencie kompilacji kompilator nie jest w stanie określić, czym jest w danej chwili, więc Monster nie ma ani metody Ryk(), ani Bzyk()*. W tym momencie przychodzą na pomoc metody wirtualne. W klasie CMonster można umieścić metodę virtual void Odglos() = 0; a w klasach pochodnych implementujesz funkcję Odgłos odpowiednio do typu zwierzęcia:
Kod: (cpp) [Zaznacz]
class CMonster
{
    //...
    virtual void Odglos() = 0;
    //...
}

class CWolf : public CMonster
{
    //...
    void Odglos()
    {
        //tutaj ryczysz
    }
    //...
}

class CWasp : public CMonster
{
    //...
    void Odglos()
    {
        //tutaj bzyczysz
    }
    //...
}
This should work. "Should" is a keyword here.

* - bez używania żadnych kombinacji typu rzutowanie.

Offline Nargil

  • Użytkownik
    • projekty

# Czerwiec 23, 2010, 20:00:19
tip 5: nie trzymaj takich wartości jak HP, Armor, dmg,str w postaci zmiennych, tylko stwórz strukturę danych. Będzie ci łatwiej podczepić język skryptowy, z poziomu którego możesz zmieniać lub tworzyć nowe wartości w grze.

Offline rm-f

  • Użytkownik
    • Tu trolluje

# Czerwiec 23, 2010, 20:13:08
@Xirdus

Kod: (cpp) [Zaznacz]
class CMonster
{
private:
   std::string sound;
public:
    CMonster(const std::string& $sound):sound($sound){};
    Odglos() {printf(chat,"%s",sound.c_str());}
};

CMonster Wolf("rooar"),Wasp("bzzz");


Tadam.

Offline Xirdus

  • Moderator

# Czerwiec 23, 2010, 20:48:29
@Świrus: a jeśli to nie ma być tekstowe tylko dźwiękowe? A jak np. ryk wilka przywołuje inne wilki, a bzyk osy nie? A jak np. ork ma kilka kwestii, z których mówi tylko jedną?

Offline rm-f

  • Użytkownik
    • Tu trolluje

# Czerwiec 23, 2010, 21:10:45
Cytuj
a jeśli to nie ma być tekstowe tylko dźwiękowe?
Kod: (cpp) [Zaznacz]
Wasp("bzzz.ogg");
Cytuj
A jak np. ork ma kilka kwestii, z których mówi tylko jedną?
A to wilk nie może drzeć się na kilka sposobów? Jeżeli przewidujemy że potwory mogą mieć kilka odzywe to ty walniesz sobie kolejne dziedziczenie i funkcje wirtualne...
A ja? Wezmę sobie zaimplementuje to, a to co ma tylko jedną odzywkę to podam tylko jedną do wyboru :-)
Cytuj
A jak np. ryk wilka przywołuje inne wilki, a bzyk osy nie?
Ty dowalisz dziedziczenie + w funkcji ryczenia wywoływanie u innych wilków tego samego (coś czego tam nie powinno być).

Pozdro Panie dziedziczony.   ;)

Offline Xirdus

  • Moderator

# Czerwiec 24, 2010, 16:14:00
Cytuj
A jak np. ryk wilka przywołuje inne wilki, a bzyk osy nie?
Ty dowalisz dziedziczenie + w funkcji ryczenia wywoływanie u innych wilków tego samego (coś czego tam nie powinno być).

Pozdro Panie dziedziczony.   ;)
Kod: (cpp) [Zaznacz]
void Ryk()
{
    if (! curSector->wilki_juz_zwolane) zwolaj_wilki();
    odegrajDzwiek("wilk_ryk_1");
    return;
}
Można też inaczej. Sposobów jest tyle ile osób rozpatrujących dany problem.

Cytuj
A jak np. ork ma kilka kwestii, z których mówi tylko jedną?
A to wilk nie może drzeć się na kilka sposobów? Jeżeli przewidujemy że potwory mogą mieć kilka odzywe to ty walniesz sobie kolejne dziedziczenie i funkcje wirtualne...
A ja? Wezmę sobie zaimplementuje to, a to co ma tylko jedną odzywkę to podam tylko jedną do wyboru :-)
A jeśli te odgłosy u orka i u wilka zależą od obecnej sytuacji, przy czym u wilka bierze się pod uwagę zupełnie inne elementy niż u orka?

Pozdro panie "Nie polimorfizmowi!".  ;)

Offline rm-f

  • Użytkownik
    • Tu trolluje

# Czerwiec 24, 2010, 16:20:09
@Xirdus
Zrozum, że (dla mnie) metoda "Ryk()", jest od ryczenia nie od logiki :|

Offline Rares

  • Użytkownik
    • Moja strona

# Czerwiec 24, 2010, 16:53:28
Temat można zakończyć jakże trafnym stwierdzeniem, że racja jest jak d*pa - każdy ma swoją ;D.

Offline Xirdus

  • Moderator

# Czerwiec 24, 2010, 17:07:17
@Xirdus
Zrozum, że (dla mnie) metoda "Ryk()", jest od ryczenia nie od logiki :|
Z tego co wiem to ryczenie przywołuje inne wilki. Chyba nie jest lepszym rozwiązaniem przy każdym obiegu pętli sprawdzać, czy przypadkiem któryś nie ryknął.

Temat można zakończyć jakże trafnym stwierdzeniem, że racja jest jak d*pa - każdy ma swoją ;D.
Mam lepsze zakończenie: C++ jest tak zaj*bisty, że jedną rzecz można zrobić na 100 sposobów, przy czym każdy będzie lepiej lub gorzej działał.