• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Klasy, obiekty

Object Storage Arubacloud
+1 głos
422 wizyt
pytanie zadane 5 listopada 2016 w C i C++ przez Mr Joker Początkujący (330 p.)

Przykładowo robię grę, w której chcę klasy: Mag, Łowca, Tropiciel. 
Każda z postaci ma takie same "elementy", ale różne ich wartości, czyli HP, Energia, Mana. 
Z kolei, każda klasa ma inną umiejętność specjalną (Mag=ściana ognia, tropiciel=płonąca strzała, łowca=grad strzał).

Teraz pytanie, czy zadziała, jak stworzę jedną klasę główną, zamieszczę w niej atrybuty oraz voidy do specjalności, a w int main () utworzę obiekty i odwołam do nich te funkcje (przykład poniżej), czy każdą klasę (Mag, Łowca, Tropiciel) będę musiał utworzyć w oddzielnym class?

Spoiler

class skills_specialum
{
    int HP;
    int energia;
    int mana;
    
    void scianaognia ()
    {
        trescfunkcji;
    }
    
    void plonacastrzala ()
    {
        trescfunkcji;
    }
    
    void gradstrzal ()
    {
        trescfunkcji;
    }
};

int main ()
{
    skills_specialum mag;
    skills_specialum tropiciel;
    skills_specialum lowca;
    mag.scianaognia();
    tropiciel.plonacastrzala();
    lowca.gradstrzal();
}

image

 

image

 

Czy to zadziała? Czy będę musiał Maga, Łowce, Tropiciela w oddzielnych klasach robić (bo przecież mają inne specjalne UM)?

komentarz 5 listopada 2016 przez Myśliwy Gaduła (3,080 p.)

chcę klasy: Mag, Łowca, Tropiciel.

Czy będę musiał Maga, Łowce, Tropiciela w oddzielnych klasach robić

Mówisz, że chcesz i pytasz się czy musisz. Nie musisz. 
Zadziała, tylko że w tym przypadku łowca będzie mógł zrobić ścianę ognia. 
Lepiej chyba zrobić oddzielne klasy do tych trzech postaci i dać im metody o tej samej nazwie, innej instrukcji tj.: W każdej klasie Mag, Łowca, Tropicel zrobić funkcję special_skill(), która użyta dla obiektu Maga zrobi ścianę ognia, a dla Łowcy grad strzał.
Wtedy:
 

Mag postac1;
Lowca postac2;

postac1.special_skill();
postac2.special_skill();

i każdy zrobi co do niego należy.

1 odpowiedź

+5 głosów
odpowiedź 5 listopada 2016 przez easytodo Mądrala (5,380 p.)
wybrane 6 listopada 2016 przez Mr Joker
 
Najlepsza

Najlepiej zrobić klasę bazową postać i 3 podklasy - mag, łowca, tropiciel. W klasie postać stworzyć wirtualne metody i w klasach dziedziczących je nadpisać. Przy używaniu klas używaj wskaźników typu postać (na tym mniej więcej polega polimorfizm). Przykład:

#include <iostream>

using namespace std;

class Postac
{
protected:
    int hp;
    int energia;
    int mana;
    //reszta atrybutow

public:
    virtual void umiejetnosc_specjalna() = 0;
};

class Mag : public Postac
{
public:
    void umiejetnosc_specjalna() { cout << "Sciana ognia" << endl; }
};

class Lowca : public Postac
{
public:
    void umiejetnosc_specjalna() { cout << "Grad strzal" << endl; }
};

int main()
{
    Postac* postac = new Mag();
    postac->umiejetnosc_specjalna();
    delete postac;

    postac = new Lowca();
    postac->umiejetnosc_specjalna();
    delete postac;
    return 0;
}

postac - wskaźnik typu Postac (typu naszej klasy bazowej). Zauważ, że reszta klas dziedziczy z klasy Postac, umożliwa to stworzenie wskaźnika typu Postac, który wskazuje na obiekty klas dziedziczących z klasy Postac (jezeli tego nie rozumiesz, nie martw się, poczytaj o polimorfiźmie i wszystko będzie jaśniejsze). 

Metoda umiejetnosc_specjalna() jest wirtualna, a więc przy wywołaniu jej z poziomu wskaźnika ( postac->umiejetnosc_specjalna() ) program "patrzy", na obiekt której klasy wskazuje wskaźnik typu Postac, a następnie wywołuje metodę z tej klasy. Bez użycia kluczowego słowa "virtual", zostałaby wywołana metoda z klasy Postac, ponieważ program sugerowałby się typem wskaźnika, a nie typem obiektu, na który wskaźnik ten wskazuje.

komentarz 5 listopada 2016 przez Mr Joker Początkujący (330 p.)
Wielkie dzięki, a powiedz mi, co oznacza:
1. class Lowca : public Postac,
2. Postac* postac = new Mag(),
3.  delete postac - dlaczego ?
komentarz 5 listopada 2016 przez easytodo Mądrala (5,380 p.)
1. Zapis ten oznacza, że klasa Lowca dziedziczy publicznie z klasy Postac. A więc wszystkie składowe klasy Postac, które znajdują się pod dyrektywami public lub protected, znajdują się też w klasie Lowca (tutaj dziedziczone jest energia, hp, mana i umiejetnosc_specjalna() ).

2. Postac* postac to wskaźnik typu Postac. (int *a to wskaźnik typu int, dokladnie tak samo jest ze wskaźnikiem typu Postac). Słówko 'new' alokuje, czyli rezerwuje pamięć dla obiektu typu Mag (bo = new Mag() ). Metoda Mag() to konstruktor klasy Mag. Możemy tutaj użyć konstruktora klasy Mag, ponieważ ta klasa dziedziczy z klasy Postac ( class Mag : public Postac ).

A więc zapis Postac* postac = new Mag() oznacza deklarację wskaźnika typu klasy bazowej Postac i przypisanie mu adresu obiektu typu Mag. (wskaźnik ten wskazuje na obiekt typu Mag).

3. delete postac - instrukcja 'delete' zwalnia adres w pamięci, pod którym znajduje się nasz obiekt typu Mag, który jest wskazywany przez wskaźnik. Generalnie bez tego delete program będzie działał, jednak obiekt Mag zostanie w pamięci aż do końca działania programu i nie będziesz mógł tej pamięci ponownie użyć, a więc przy, powiedzmy, 100 000 stowrzeniach obiektu Mag nie używając delete, tracisz 100 000 komórek w pamięci (przy założeniu 1 obiekt Mag = 1 komórka :) ).

Wiem że to może być skomplikowane, jeżeli nie wiesz co to dziedziczenie lub polimorfizm, lub nie do końca je rozumiesz, polecam lekturę:
http://xion.org.pl/productions/texts/coding/megatutorial/

Oraz kurs Pana Mirsoława, jednak koniecznie musi być on później czymś uzupełniony (w Internecie jest masa poradników i tutoriali :) ):
https://www.youtube.com/watch?v=aDXjubGK0jU
komentarz 5 listopada 2016 przez Mr Joker Początkujący (330 p.)
A nie wystarczy zrobić, tak jak podał kolega wyżej? :)
komentarz 5 listopada 2016 przez easytodo Mądrala (5,380 p.)
edycja 5 listopada 2016 przez easytodo

Na początek jak najbardziej, ale użycie polimorfizmu bardzo upraszcza kod oraz przyspiesza jego działanie.Załóżmy, że w naszej grze gracz ma do wyboru 3 klasy postaci. Rozważmy wygląd funkcji, która odpowiada za wykonywanie ataku:

if (wybrana_postac == mag)
{
    mag.special_skill();
}

else if (wybrana_postac == lowca)
{
    lowca.special_skill();
}

else if (wybrana_postac == tropiciel)
{
    tropiciel.special_skill();
}

Zamiast tego, użyjmy wskaźnika typu klasy podstawowej wskazującego na dowolną klasę która dziedziczy po klasie bazowej. Nie ważne czy będzie to lowca, mag czy tropiciel, wywloanie special skilla będzie zawsze wyglądało tak samo:

postac->special_skill();

A więc skracamy kod i poprzez ominięcie wielu ifów przyspieszamy program. Uwierz mi, że jest to bardzo wygodne, nie tylko w przypadku ataku, ale w wielu wielu innych przypadkach. 

Takim innym przypadkiem może być na przykład sytuacja, w której chcesz sprawdzić kolizję twojego bohatera z otoczeniem (np czy nie dobijasz do ściany). Dla 3 różnych postaci musiałbyś napisać 3 funkcje przyjmujące różne argumenty, a mające dokładnie te same "bebechy". 

void sprawdz_kolizje(Mag mag)
{
    //jakis kod
}

void sprawdz_kolizje(Lowca lowca)
{
    //ten sam kod co wyzej
}

void sprawdz_kolizje(Tropiciel tropiciel)
{
    //ten sam kod co wyzej
}

Tak jak widać, mamy 3 funkcje, które robią dokładnie to samo, a nie jest to przez nas pożądane. Zamiast tego, używając polimorfizmu, możemy użyć tylko 1 funkcji, która będzie przyjmować wszystkie 3 rodzaje postaci (przy użyciu wskaźnika).

void sprawdz_kolizje(Postac* postac)
{
    //sprawdzanie kolizji bez znaczenia, na ktora postac wskazuje wskaznik
}

 

komentarz 5 listopada 2016 przez Mr Joker Początkujący (330 p.)
Okej, bardzo Ci dziękuję!
komentarz 5 listopada 2016 przez easytodo Mądrala (5,380 p.)
Nie ma sprawy w razie niejasności pytaj, odpowiem w miarę możliwości :)

Podobne pytania

+1 głos
1 odpowiedź 303 wizyt
pytanie zadane 21 lutego 2021 w C# przez Bartosz Paterek Początkujący (410 p.)
0 głosów
1 odpowiedź 489 wizyt
pytanie zadane 9 września 2020 w PHP przez Młody programista Obywatel (1,200 p.)
0 głosów
1 odpowiedź 265 wizyt
pytanie zadane 16 czerwca 2020 w C i C++ przez NieMamPojecia Nowicjusz (120 p.)

92,614 zapytań

141,465 odpowiedzi

319,773 komentarzy

61,996 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...