2012-10-22 12 views
6

Buduję prosty projekt gry dla mojego projektu. Mam następujące klasy:Wskaźnik odlewania od typu podstawowego do typu dziecka

class Character 
{ 
public: 
    virtual void Display(); 
    virtual void SetParameters(char* param, ...); 
}; 

class NonPlayableCharacter : public Character 
{ 

public: 
    virtual void Display(); 
    virtual void SetParameters(char* paaram, ...); 
    int GetNPCState(); 
} 

A potem mam kilka klas, które wynikają zarówno z charakteru lub NonPlayableCharacter. Definiuję to tak:

std::vector<Character*> _allChar; 

Mój problem polega na tym, że w dowolnym momencie chciałbym wykonać operację na jednym z elementów wektora. Tak więc wyjęcie elementu z wektora nie mogę bezpośrednio nazwać metodą GetNPCState(), ponieważ element w wektorze jest typu Character *. Robiąc to:

_allChar[0]->GetNPCState(); 

nie działa. Więc próbowałem to robić ze słynnym dynamic_cast:

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]); 
test->GetNPCState(); 

Problem z tej ostatniej próbie, że GetNPCState() awarii, ponieważ obiekt jest null, i wiem na pewno, że (przez debugowania), które _allChar [0] ISN” t null.

+2

Otrzymujesz zerowy wskaźnik, gdy obiekt, który próbujesz rzucić na NonPlaya bleCharacter' nie jest tak naprawdę 'NonPlayableCharacter'. Prawdopodobnie niektóre z obiektów w wektorze pochodzą bezpośrednio z 'Character'. – jogojapan

+0

Na marginesie pracuję z komponentem (elementami), który wykorzystuje wiele wektorów wskaźników. Spowodowało to dla mnie wiele kłopotów, ponieważ ten wektor kończy się czasami wskaźnikami usuniętej pamięci i prowadzi do uszkodzenia pamięci. Myślę, że używasz wektora wskaźnika, ponieważ używasz go polimorficznie i/lub obiekty są udostępniane.W obu przypadkach zdecydowanie zaleciłbym zmianę twojego wektora, by utrzymywał współdzielony typ wskaźnika (np. 'Std :: shared_ptr' lub zmienił twój wektor na' boost :: ptr_vector' (co jest świetne w obu scenariuszach). Powodzenia w grze! – Dennis

Odpowiedz

6

Istnieje kilka rodzajów odlewów w C++ (4), z których 2 są interesów tutaj:

  • static_cast zakłada, że ​​wiesz, co robisz
  • dynamic_cast kontrole, w czasie wykonywania , że „domyślić” prawo

Uwaga: uproszczony, jako dynamic_cast pozwala również krzyżowe odlewane i rzuca involvi ng wirtualnych baz.

Istnieją 3 wersje dynamic_cast, naprawdę, w zależności od charakteru docelowa:

  • jeśli cel jest odwołaniem (tj dynamic_cast<T&>(u)), a następnie, jeśli kontrola nie dynamic_cast rzuca std::bad_cast wyjątek
  • jeśli cel jest wskaźnik (tj dynamic_cast<T*>(p)), a następnie sprawdza, czy nie dynamic_cast zwraca null pointer
  • wreszcie, jako szczególny przypadek, gdy cel jest void*, a następnie dynamic_cast zamiast zwraca adres pełnego obiektu

W tym przypadku, możesz:

  • przełącznik od dynamic_cast<NonPlayableCharacter*>(_allChar[0])->getNPCState() do dynamic_cast<NonPlayableCharacter&>(*_allChar[0]).getNPCState() i niech wyjątek propaguje
  • testu wynikiem obsada (NonPlayableCharacter* test) dla braku nieważności
3

dynamic_cast zwraca NULL jeśli oddanie jest niemożliwe. Sprawdź, co jest w środku _allChar[0]. Można zrobić funkcję jak getType() gdzie powraca obiekt predefiniowany typ identyfikatora, a następnie użyć static_cast:

if (_allChar[0]->getType() == TYPE_NO_PLAYER) { 
    static_cast<NonPlayableCharacter*>(_allChar[0])->getNpcState(); 
} 
5

Po

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]); 

należy sprawdzić, czy test jest NULL. Nawet jeśli _allChar[0] nie ma wartości NULL, dynamic_cast może zwrócić NULL, jeśli obiekt, na który wskazuje, nie jest NonPlayableCharacter.

więc poprawna wersja będzie:

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]); 
if (test) 
{ 
    test->GetNPCState(); 
} 
2

Trzeba przetestować dynamic_cast sukcesu. Zwraca null pointer po awarii:

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]); 
if (test) test->GetNCPState(); 

Problem może być, że pierwszy element nie wskazują na NonPlayableCharacter obiektu.

2

dynamic_cast powraca NULL gdy jej argument nie wskazują na NonPlayableCharacter (więc pierwszy element tablicy prawdopodobnie wskazuje na jakiś inny podklasy Character) - więc trzeba sprawdzić NULL po gipsie. Jednak użycie dynamic_cast może wskazywać na problem projektowy. Być może powinieneś zamiast tego mieć wirtualną metodę na Character, która jest wywoływana np. PerformMainActionInGameLoop() i jest odpowiednio nadpisany w różnych podklasach?

2

Aby uzyskać wskaźnik podrzędny ze wskaźnika bazowego, należy użyć dynamic_cast.Jego zachowanie jest następujące:

  • Jeśli punkty wskaźnik do Child* przydzielonego z new Child następnie dynamic_cast<Child*> zwraca Child*
  • Jeśli punkty wskaźnik do czegoś innego, a następnie dynamic_cast powraca NULL.

Twój problem polega na tym, że nie utworzyłeś przydziału z new lub Twój obiekt jest innego typu.

2

Prawdopodobnie istnieje lepsze rozwiązanie OO do używania dynamic_cast, ale cały punkt używania tego rzutowania jest taki, że zwróci wskaźnik NULL, jeśli rzutowanie nie powiedzie się.

Sprawdź więc NULL przed wywołaniem GetNPCState();

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]); 
if(test != NULL) 
{ 
    test->GetNPCState(); 
} 
Powiązane problemy