web-dev-qa-db-fra.com

c ++ - conversion d'un pointeur de classe de base en un pointeur de classe dérivé

#include <iostream>
using namespace std;

class Base {
public:
  Base() {};
  ~Base() {};
};

template<class T>
class Derived: public Base {
  T _val;
public:
  Derived() {}
  Derived(T val): _val(val) {}
  T raw() {return _val;}
};

int main()
{
  Base * b = new Derived<int>(1);
  Derived<int> * d = b;
  cout << d->raw() << endl;
  return 0;
}

J'ai un problème de polymorphisme en ce moment et le code ci-dessus résume tout. J'ai créé un pointeur de classe Base et j'y ai placé le pointeur d'une nouvelle classe de modèle dérivée. J'ai ensuite créé un nouveau pointeur pour la classe de modèle dérivée et je veux qu'il ait la référence vers laquelle pointe le pointeur de la classe de base. Même si le pointeur de base (b) pointe vers un dérivé, la référence ne peut pas être transmise au pointeur de classe dérivée (d) car there's no known conversion from Base * to Derived<int> * (comme le dit le compilateur).

Existe-t-il donc une astuce ou une alternative pour pouvoir le faire? Merci d'avance.

22
Andy Autida

Vous devez changer le type de base pour qu'il soit polymorphe:

class Base {
public:
    Base() {};
    virtual ~Base(){};
};

Pour transtyper d'un supertype vers un type dérivé, vous devez utiliser dynamic_cast:

Base *b = new Derived<int>(1);
Derived<int> *d = dynamic_cast<Derived<int> *>(b);

En utilisant dynamic_cast ici vérifie que le transtypage est possible. S'il n'est pas nécessaire d'effectuer cette vérification (car la conversion ne peut pas échouer), vous pouvez également utiliser static_cast:

Base *b = new Derived<int>(1);
Derived<int> *d = static_cast<Derived<int> *>(b);
41
Abrixas2

Essaye ça:

Derived<int> * d = static_cast<Derived<int>* >(b);

inconvénient, vous pouvez transtyper une classe qui est une instance de Base (), puis d-> raw () ne sera pas défini (faute de segmentation likley). Si cela peut être le cas, utilisez dynamic_cast et ayez au moins une fonction ob base virtual (avoir des destructeurs virtuels est essentiel lorsque vous travaillez avec le polmorphisme).

Les fonctions virtuelles sont sous le capot implémentées à l'aide d'un pointeur sur une table virtuelle. Ce pointeur peut également être utilisé pour identifier le vrai type de classe. Ceci est utilisé par dynamic_cast pour vérifier si cette conversion peut être effectuée et apporte une petite surcharge supplémentaire lors de la conversion.

2
Luka Rahne

Vous pouvez utiliser dynamic_cast

Derived<int> * d = dynamic_cast<Derived<int> *>(b);

Si le transtypage échoue (le pointeur de base ne pointe pas vers le type dérivé demandé), il renvoie null.

Cependant, pour que dynamic_cast fonctionne, votre classe de base doit avoir au moins une fonction virtuelle. Je vous suggère de rendre le destructeur virtuel (cela évite également d'autres problèmes potentiels de suppression de vos objets).

L'utilisation de dynamic_cast peut indiquer une mauvaise conception dans votre code.

Notez que si vous êtes sûr à 100% que le pointeur de base pointe vers votre type dérivé, vous pouvez le remplacer par static_cast, qui est légèrement plus rapide. Personnellement, je préfère le contrôle de sécurité supplémentaire en général.

2
Neil Kirk