Question

Dans le code suivant, lors de la construction obj dans le cas 1, nous construisons un objet de classe derived aussi, mais ses fonctions membres sont tout simplement inaccessibles à obj. Ainsi, alors que coulée en descente (à savoir, dans le cas 2), en utilisant obj en tant que source, nous avons le derived construit déjà. Pourquoi aurait obj besoin d'être polymorphes?

Si je vous confondre avec ma description ci-dessus, pourquoi ne pas obj besoin d'être polymorphes quand transtypage ascendant, mais tout ce coulée en descente ne besoin d'être polymorphes en utilisant dynamic_cast?

class base
{
public:
    base()
    {
        cout<< " \n base constructor \n";
    }
};

class derived : public base
{
public:
    derived()
    {
        cout << " \n derived constructor \n";
    }
};

base *obj = dynamic_cast<base*> (new derived); // case 1: explicitly upcasting
derived *OBJ = dynamic_cast<derived*> (obj);   // case 2: error
Était-ce utile?

La solution

De 5.2.7 / 1 [expr.dynamic.cast]:

  

Le résultat de l'dynamic_cast<T>(v) d'expression est le résultat de la conversion de l'expression v taper   T.

     

[...]

     

Si T est "pointeur CV1 B" et v est de type "pointeur CV2 D" tel que B est une classe de base de D, le résultat est   pointeur sur le sous-objet B unique de l'objet pointé par D v.

     

[...]

     

Sinon , v est un pointeur ou une lvalue d'un type polymorphes.

La norme fournit même l'exemple suivant qui illustre que l'exigence de type polymorphes ne représente pas dérivé à la conversion de base:

struct B {};
struct D : B {};
void foo(D* dp)
{
    B* bp = dynamic_cast<B*>(dp); // equivalent to B* bp = dp;
}

Autres conseils

dynamic_cast pour travailler les besoins d'objet à polymorphes. La raison en est que dynamic_cast a besoin un endroit pour stocker les informations de type qui utilisera pour effectuer la distribution, et il le fait en stockant les informations à côté de la vtable pour la classe. Pour qu'il y ait un vtable vous devez faire au moins un de vos méthodes virtuelles.

La meilleure façon de contourner cela est de marquer la classe de base destructor comme virtuelle.

Transtypage ascendant (ie dérivé à la base) ne doit pas CAST le compilateur est en mesure de vérifier que le casting travaillerait au moment de la compilation. Cependant, le même n'est pas vrai quand coulée en descente.

dynamic_cast

  • Il est utilisé pour jeter un pointeur de base en un pointeur dérivé. Si la base pointeur ne pointe pas vers un objet de le type de dérivé, il retourne
  • Il est utilisé pour jeter une référence de base en une référence dérivée. Si la référence ne pointe pas vers un objet de la dérivée, il jette :: bad_cast std.
  • On peut considérer la distribution vérifiée équivalent à static_cast, en ce qu 'il vérifie si l'objet pointé est vraiment du type dérivé.

Vous devez en savoir plus sur dynamic_cast (par exemple) il.

B* b = new D();
D* d = dynamic_cast<D*>(b);

Dans l'exemple ci-dessus la plupart des compilateurs mettrait en œuvre dynamique en vérifiant casting si le pointeur vtable de points b à la vtable de la classe dérivée D ou non. Si oui, il retourne simplement l'adresse de b que la valeur de retour sinon il retourne un nullptr. Ceci est peut-être ce qui se passe dans les coulisses lors de l'exécution d'coulées de dynamique: -

class car
{
    public:
    virtual void drive()
    {
         std::cout <<"car"<<std::endl;
    }
};
class toyota: public car
{
    public:
    virtual void drive()
    {
        std::cout <<"toyota"<<std::endl;
    }
};

class honda: public car
{
    public:
        virtual void drive()
    {
        std::cout <<"honda"<<std::endl;
    }
};

template <typename Tderived>
Tderived* dynamicCast(void* pBase)
{
    //compare the vptr of the class pointed by pBase with a temporary Tderived class. 
    //If vptr of pBase and vptr of Tderived() are pointing to the same vtable 
    //then it can be safely deduced that pBase is indeed pointing to an instance of Tderived
    if (*(int**)pBase == *(int**)&Tderived())
    {
        return (Tderived*)pBase;
    }
    else
    {
        return nullptr;
    }
}


int main()
{
    car* pCar;
    honda hondaCar;
    toyota toyotaCar;

    pCar = &toyotaCar;

    honda* pHonda = dynamicCast<honda>(pCar);
    if (nullptr != pHonda)
    {
        pHonda->drive();
    }
    else
    {
        toyota* pToyota = dynamicCast<toyota>(pCar);
        if (nullptr != pToyota)
        {
            pToyota->drive();
        }
    }
}

Maintenant, si la classe est pas polymorphes, il n'y a aucun moyen pour le compilateur de trouver si PCAR pointe à la voiture honda ou toyota. Notez que ceci est juste une des façons de mettre en œuvre dynamic_cast comme le standard C ++ ne parle pas rien vtables.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top