virtual + polimorfizm a przeciążanie funkcji

Odpowiedz Nowy wątek
2018-09-14 11:05
0

Cześć!

Pisząc grę napotkałem problem. Dziedziczenie wygląda tak : cPostac->cGracz/cWrog
Chcę przekazać wrogowi pozycję gracza, żeby mógł w niego wycelować.
cPostac ma metodę : virtual void aktualizuj(float pobranyCzas);, cGracz nie ma potrzeby przekazywania czegoś innego niż czas więc nic nie nadpisywałem.
metoda aktualizuj aktualizuje następująco : poruszanie, animację i strzelanie. Strzelanie wymaga pozycji gracza więc wygląda to tak:

wrogów mam zapisanych w
std::vector<std::unique_ptr<cPostac>> Wrogowie;

//main.cpp
        for (auto const& i : Wrogowie)
            i->aktualizuj(timer1.getElapsedTime().asSeconds(), Gracz->zwrocPozycje()); 
void cWrog::aktualizuj(float pobranyCzas, sf::Vector2f pozcyjaGracza)
{
    aktualizujAnimacje(pobranyCzas);

    if (oddawanieStrzalu == false)
        aktualizujPolozenie(pobranyCzas);

    aktualizujStrzelanie(pobranyCzas, pozcyjaGracza);
}

->

void cWrog::aktualizujStrzelanie(float pobranyCzas, sf::Vector2f pozycjaGracza)
{
//...
        wycelujStrzelba(pozycjaGracza);
//...
}

->

void cWrog::wycelujStrzelba(sf::Vector2f pozycjaGracza)
{
    //algorytm celowania
}

Wiem, że to może być bez sensu takie przekazywanie ale chcę rozbijać te funkcje na jak najprostsze no i nie chcę w mainie wywoływać każdej funkcji (aktualizuj polozenie, animacje strzelanie) bo nie zawsze aktualizuje je na raz w logice gry.

Korzystając z tego tematu zbudowałem podobny program, który obrazuje moją sytuację:

#include <iostream>
#include <vector>
#include <memory>

struct A {
    virtual void Show() const { std::cout << __FUNCTION__ << '\n'; }
};

struct B : public A {
    virtual void Show(int a) const  { std::cout << __FUNCTION__  << a << '\n'; }
};

struct C : public A {
    virtual void Show(int a, int b) const  { std::cout << __FUNCTION__ << a << b << '\n'; }
};

int main() {
    std::vector<A> objects;
    objects.push_back(B{});
    objects.push_back(C{});

    std::vector<std::unique_ptr<A>> ptrs;
    ptrs.push_back(std::make_unique<B>());
    ptrs.push_back(std::make_unique<C>());

    std::cout << "Kontener objects: \n";
    objects[0].Show();
    objects[1].Show(1);
    objects[2].Show(1, 2);

    std::cout << "Kontener ptrs: \n";
    ptrs[0]->Show();
    ptrs[1]->Show(1);
    ptrs[2]->Show(1, 2);

    std::cin.get();
}

w przekazywaniu Show() intów wywala błąd, bez wartości działa poprawnie. Jak mogę rozwiązać ten problem ?

edytowany 3x, ostatnio: kameleo327, 2018-09-14 11:11

Pozostało 580 znaków

2018-09-14 11:11
1
std::vector<A> objects;
objects.push_back(B{});

Czego tutaj się spodziewasz? objects potrafi przechowywać wyłącznie elementy typu A.


Pozostało 580 znaków

2018-09-14 11:13
0
pingwindyktator napisał(a):
std::vector<A> objects;
objects.push_back(B{});

Czego tutaj się spodziewasz? objects potrafi przechowywać wyłącznie elementy typu A.

No dobra, tutaj to ja rozumiem. Ale ptrs ?

Po co dodawać pośredni sposób odwołania od obiektów skoro istnieje bezpośredni?

Pozostało 580 znaków

2018-09-14 12:28
5

Jak korzystasz z polimorfizmu, musisz korzystać ze wskaźników, inaczej nie ma to sensu, bo nie ma polimorfizmu.
Polimorfizm i overloading to bardzo nietrafione połączanie. Oczywiście, że się da, ale po co? Powoduje to więcej kłopotów niż zysków.

Kiedyś ktoś mi napisał interface z przeciążonymi metodami. Jak go musiałem zaimplementować to musiałem napisać kod, który niczego nie wnosił (było 5 przeciążeń i tylko jeden miał sensowny kod reszta tylko zaspakajała przeciążenie wywołując tą jedną metodę). I tak za każdym razem kiedy implementowało się interface.
Interface (klasa tylko z metodami czysto witalnymi) zwykle stanowi deficjencję wymagań dla obiektu, ergo im mniejsze wymagania się stawia (mniej metod), tym łatwiej je zaspokoić i łatwiej utrzymać kod.
Mimo, że interface to przypadek szczególny, to IMO pokazuje ogólną zasadę bezsensowności przeciążeń dla metod wirtualnych.

Dlatego uważam, że przeciążanie powinno być wyłącznie dla metod niewirtualnych, a jeszcze lepiej jeśli jest używane jedyni dla klas o naturze struktury (coś czego kopiowanie ma sens), a nie obiektu.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: MarekR22, 2018-09-14 12:44

Pozostało 580 znaków

2018-09-14 12:53
1

Funkcje wirtualne tak nie działają. Nie możesz w klasie dziedziczącej zmieniać parametrów przyjmowanych przez funkcję z klasy bazowej. Moim zdaniem źle podchodzisz do problemu i przekazywanie różnych parametrów w metodzie aktualizuj w ogóle nie jest potrzebne. Zrób sobie klasę Świat, która będzie zawierała informacje o świecie i kontenery z postaciami, potem w każdej klasie Postać daj wskaźnik na Świat i niech każda Postać w metodzie void aktualizuj() sobie pobiera ze świata potrzebne jej informacje, takie jak czas, wskaźnik na gracza itd.

Pozostało 580 znaków

2018-09-14 14:44
1

Albo niech klasa cPostac posiada wskaźnik na cPostac, który będzie określał kogo ma atakować + do tego funkcja UstawCel.

Pozostało 580 znaków

2018-09-15 11:35
0

Dodałem przeciążenie do aktualizuj(); i nie działało. Zmieniłem typ wskaźnika z cPostac na cWrog i śmiga std::vector<std::unique_ptr<cWrog>> Wrogowie; Na razie niech tak zostanie.
Podoba mi się pomysł z klasą świat. Kiedyś przetestuję :)

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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