Question

Je vais avoir un peu de mal avec dynamic_casting. Je dois déterminer à l'exécution du type d'un objet. Voici une démo:

#include <iostream>
#include <string>

class PersonClass
{
  public:
  std::string Name;
  virtual void test(){}; //it is annoying that this has to be here...
};

class LawyerClass : public PersonClass
{
  public:
  void GoToCourt(){};
};

class DoctorClass : public PersonClass
{
  public:
  void GoToSurgery(){};
};

int main(int argc, char *argv[])
{

  PersonClass* person = new PersonClass;
  if(true)
  {
    person = dynamic_cast<LawyerClass*>(person);
  }
  else
  {
    person = dynamic_cast<DoctorClass*>(person);
  }

  person->GoToCourt();


  return 0;
}

Je voudrais faire ce qui précède. La seule façon juridique que je trouve de le faire est de définir tous les objets avant la main:

  PersonClass* person = new PersonClass;
  LawyerClass* lawyer;
  DoctorClass* doctor;

  if(true)
  {
    lawyer = dynamic_cast<LawyerClass*>(person);
  }
  else
  {
    doctor = dynamic_cast<DoctorClass*>(person);
  }

  if(true)
  {
    lawyer->GoToCourt();
  }

Le principal problème avec cette (en plus d'avoir à définir un tas d'objets qui ne seront pas l'utilisation) est que je dois changer le nom de la variable « personne ». Est-il possible de mieux?

(je ne suis pas autorisé à modifier les classes (personne, avocat ou médecin) parce qu'ils font partie d'une bibliothèque que les gens qui utiliseront mon code ont et ne voudront pas changer).

Merci,

Dave

Était-ce utile?

La solution

Dynamique coulée à une sous-classe, puis attribuer le résultat à un pointeur vers superclasse est d'aucune utilité - vous êtes pratiquement où vous avez commencé. Vous avez besoin d'un pointeur vers une sous-classe pour stocker le résultat de la distribution de dynamique. En outre, si le type de béton de votre objet est PersonClass, vous ne pouvez pas baissés à une sous-classe. coulée dynamique ne peut travailler pour vous si vous avez un pointeur vers une superclasse mais vous savez que l'objet pointé est en fait une instance d'une sous-classe .

Comme d'autres l'ont souligné aussi, la meilleure option serait de redessiner la hiérarchie des classes pour faire vos méthodes vraiment polymorphes, éliminer ainsi la nécessité de downcasting. Puisque vous ne pouvez pas toucher ces classes, vous avez besoin baissés. La façon typique d'utiliser ce serait quelque chose comme

PersonClass* person = // get a Person reference somehow

if(/* person is instance of LawyerClass */)
{
  LawyerClass* lawyer = dynamic_cast<LawyerClass*>(person);
  lawyer->GoToCourt();
}
else
{
  DoctorClass* doctor = dynamic_cast<DoctorClass*>(person);
  doctor->GoToSurgery();
}

Mise à jour: si vous souhaitez utiliser les instances de sous-classe plus tard, vous pouvez le faire de cette façon:

PersonClass* person = // get a Person reference somehow
...
LawyerClass* lawyer = NULL;
DoctorClass* doctor = NULL;

if(/* person is instance of LawyerClass */)
{
  lawyer = dynamic_cast<LawyerClass*>(person);
}
else if(/* person is instance of DoctorClass */)
{
  doctor = dynamic_cast<DoctorClass*>(person);
}
...
if(lawyer)
{
  lawyer->GoToCourt();
}
else if (doctor)
{
  doctor->GoToSurgery();
}

Notez que ce code est plus compliqué et plus sujette aux erreurs que la version précédente. Je certainement essayer de factoriser ce code pour le rendre plus comme la version précédente. YMMV.

Autres conseils

Si elles ne sont pas des fonctions polymorphes (comme la réponse de David les définit comme), faisant alors cela va être plus difficile.

Je suggère une classe wrapper.

class PersonWrapper {
    PersonClass* person;
    virtual void DoWork() = 0;
};
class DoctorWrapper : public PersonWrapper {
    DoctorClass* doc;
    virtual void DoWork() { doc->GoToSurgery(); }
};
class LawyerWrapper : public PersonWrapper {
    LawyerClass* lawyer;
    virtual void DoWork() { lawyer->GoToCourt(); }
};

Bien sûr, cela laisse quelques détails de mise en œuvre à définir par vous, comme attribuer le pointeur dans des conditions correctes, et est une utilisation laide du tas. Cependant, il devrait offrir des fonctionnalités polymorphes, en ce que vous pouvez maintenant faire

PersonWrapper* wrap = new LawyerWrapper(new LawyerClass());
wrap->DoWork();

Je n'envisager d'utiliser ce genre de solution si vous êtes vraiment désespéré.

peut être tout à fait manquer le point ici ou je peux être tout malentendu, par exemple si je suis moi savoir et je vais supprimer mon poste.

Mais ne serait-il pas plus logique d'avoir une méthode publique appelée doJob (ou quelque chose de similaire) qui appelle la méthode virtuelle. De cette façon, vous pouvez faire ceci:

#include <iostream> 
#include <string> 
using namespace std;

class PersonClass 
{ 
public: 
    std::string Name; 
    virtual void doWork(){}; //it is annoying that this has to be here... 
}; 

class LawyerClass : public PersonClass 
{ 
public: 
    void doWork(){GoToCourt();}
    void GoToCourt(){cout<<"Going to court..."<<endl;} 
}; 

class DoctorClass : public PersonClass 
{ 
public: 
    void doWork(){GoToSurgery();}
    void GoToSurgery(){cout<<"Doing surgery..."<<endl;}; 
}; 

int main(int argc, char *argv[]) 
{ 

    PersonClass* person; 
    if(true) 
    { 
        person = new LawyerClass(); 
    } 
    else 
    { 
        person = new DoctorClass(); 
    } 

    person->doWork(); 


    return 0; 
} 

Est-il possible pour vous d'ajouter une cale aux classes comme ceci:

class Person
{
public:
    virtual void DoJob() = 0;
};

class Lawyer : public Person, public LawyerClass
{ 
public:
    virtual void DoJob()  { GoToCourt(); }
}; 

class Doctor : public Person, public DoctorClass
{ 
public:
    virtual void DoJob() { GoToSurgery(); }
}; 

void DoJob(Person& person)
{
    person.DoJob();
}

int main(int argc, char *argv[]) 
{
    Doctor doctor;
    Lawyer lawyer;
    DoJob(doctor); // Calls GoToSurgery();
    DoJob(lawyer); // Calls GoToCourt();
    return 0;
} 

De cette façon, vous ne devez utiliser un conditionnel. Mais ce qui est vraiment un « dernier recours » solution si vous ne pouvez vraiment pas modifier le code bibliothèque existante, et il ne nécessite vos utilisateurs d'utiliser Doctor et Lawyer au lieu de DoctorClass et LawyerClass.

dynamic_cast vous permet d'obtenir un plus précisément typé référence ou pointeur sur un objet d'un type donné.

Il ne vous permet pas de changer le type de l'objet. Le type d'un objet construit ne peut pas changer en C ++. Vous devez construire un nouvel objet.

LawyerClass lawyer( person );

EDIT: pour adapter votre échantillon dans une démonstration approximative de polymorphisme,

  PersonClass* person = NULL;
  if(true)
  {
    person = new LawyerClass;
  }
  else
  {
    person = new DoctorClass;
  }

  if ( LawyerClass *lawyer = dynamic_cast< LawyerClass * >( person ) )
  {
    lawyer->GoToCourt();
  }

En outre, vous devez utiliser un destructeur virtuel « vide » plutôt que virtual void test() {}.

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