8 votes

Casting un pointeur d'un type de base vers un type enfant

Je construis un design de jeu simple pour un de mes projets. J'ai les classes suivantes:

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();
}

Et puis j'ai plein de classes qui dérivent soit de Character soit de NonPlayableCharacter. Je les définis comme ceci:

std::vector _allChar;

Mon problème est qu'à tout moment donné, je voudrais effectuer une opération sur un des éléments du vecteur. Donc, en récupérant un élément du vecteur, je ne peux pas appeler directement la méthode GetNPCState() car les éléments dans le vecteur sont de type Character*. Donc en faisant ceci:

_allChar[0]->GetNPCState();

ne fonctionne pas. J'ai donc essayé de le faire avec la célèbre dynamic_cast:

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

Le problème avec cette dernière tentative est que GetNPCState() plante car l'objet est nul, et je sais de manière certaine (via le débogage) que _allChar[0] n'est pas nul.

6voto

Matthieu M. Points 101624

Il existe plusieurs types de conversions en C++ (4), dont 2 sont d'intérêt ici:

  • static_cast suppose que vous savez ce que vous faites
  • dynamic_cast vérifie, à l'exécution, que vous avez "deviné" correctement

_Remarque: simplifié, car dynamic_cast permet également les conversions croisées et les conversions impliquant des bases virtuelles._

Il existe en fait 3 versions de dynamic_cast, selon la nature de la cible:

  • si la cible est une référence (c'est-à-dire dynamic_cast(u)), alors si la vérification échoue, dynamic_cast lance une exception std::bad_cast
  • si la cible est un pointeur (c'est-à-dire dynamic_cast(p)), alors si la vérification échoue, dynamic_cast renvoie un pointeur nul
  • enfin, en tant que cas spécial, si la cible est void*, alors dynamic_cast renvoie plutôt l'adresse de l'objet complet

Dans ce cas, vous pouvez:

  • passer de dynamic_cast(_allChar[0])->getNPCState() à dynamic_cast(*_allChar[0]).getNPCState(), et laisser l'exception se propager
  • tester le résultat de la conversion (NonPlayableCharacter* test ici) pour vérifier qu'il n'est pas nul

5voto

Luchian Grigore Points 136646

Après

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

vous devriez vérifier si test est NULL. Même si _allChar[0] n'est pas NULL, le dynamic_cast peut retourner NULL si l'objet auquel il pointe n'est pas un NonPlayableCharacter.

Donc la version correcte serait:

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

3voto

Denis Ermolin Points 4015

dynamic_cast retourne NULL si la conversion est impossible. Vérifiez ce qui se trouve à l'intérieur de _allChar[0]. Vous pourriez créer une fonction comme getType() qui renvoie l'identifiant de type prédéfini de l'objet, puis utiliser static_cast :

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

2voto

juanchopanza Points 115680

Vous devez tester le dynamic_cast pour vérifier s'il réussit. Il renvoie un pointeur nul en cas d'échec :

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

Le problème pourrait être que votre premier élément ne pointe pas vers un objet NonPlayableCharacter.

2voto

Aasmund Eldhuset Points 17036

dynamic_cast retourne NULL lorsque son argument ne pointe pas vers un NonPlayableCharacter (donc le premier élément du tableau pointe probablement vers une autre sous-classe de Character) - vous devez donc vérifier le NULL après le cast. Cependant, l'utilisation de dynamic_cast pourrait indiquer un problème de conception. Peut-être devriez-vous plutôt avoir une méthode virtuelle sur Character qui est appelée par exemple PerformMainActionInGameLoop() et qui est correctement surchargée dans les différentes sous-classes?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X