Comment vérifier si un objet implémente une interface?

Comment vérifier si un objet implémente une interface? - C++ - Programmation

Marsh Posté le 09-10-2011 à 23:30:08    

Bonjour,
 
Je regarde de la doc sur le net et sur des bouquins, mais je n'arrive pas à trouver de méthode complète et saine pour gérer les interfaces en C++ (sans faire du COM).  
 
Mon problème est que j'ai plusieurs objets hétéroclites, certains ayant une "interface" A(ils héritent de A, A ayant des fonctions virtuelles et d'autres pas, un des mécanismes que je retrouve le plus dans les doc sur les interfaces) , d'autres non. Je stocke dans un tableau de void* des pointeurs sur ces objets.(car ils subissent un traitement commun). Néanmoins, j'aimerai être capable dans ce traitement d'utiliser des méthodes de l'interface A si l'objet la possède.
 
Or le castage "comme en C" ne me permet pas de savoir si ce que je récupère implémente l'interface, et le dynamic_cast n'accepte pas les void*

Code :
  1. Class A { std::string getName(); };
  2. Class B: public A {};
  3. Class C{};
  4. void* element;
  5. ...
  6. A* itf = (A*) element;
  7. itf->getName(); //OK si element est en fait un objet B, Run Time error si c'est C


 
Est-ce qu'on peut implémenter à moindre frais un genre de QueryInterface, ou est-ce que je vais être obligé de faire hériter toutes mes classes type B et C d'une classe "bidon" qui ne sert à rien sauf à ne pas utiliser de void *(et je ne sais pas si c'est plus propre)? Ou il y a t-il une autre solution pour vérifier si l'objet a bien l'interface(et je conserve donc mes void*)
 
 
Merci


---------------
I guess my real ennemy is me
Reply

Marsh Posté le 09-10-2011 à 23:30:08   

Reply

Marsh Posté le 10-10-2011 à 06:53:18    

http://www.boost.org/doc/libs/1_47 [...] se_of.html

 

boost::is_base_of<A,B>::value renvoit true si B herite de A

 


Ensuite, ton void* est une merde infame. Utilise le polymorphisme proprement en redant getName() virtuelle

 
Code :
  1. class A { virtual std::string getName(); };
  2. class B: public A {};
  3. class C{};
  4. A* element = new B;
  5. element->getrName();

`

 


Revoir les bases me parait une bonne idée. On ne C-cast pas des objets et surtout pas a partir d'un void*.

 


Message cité 1 fois
Message édité par Joel F le 10-10-2011 à 06:58:37
Reply

Marsh Posté le 10-10-2011 à 19:03:58    

Joel F a écrit :

http://www.boost.org/doc/libs/1_47 [...] se_of.html
 
boost::is_base_of<A,B>::value renvoit true si B herite de A
 
 
Ensuite, ton void* est une merde infame. Utilise le polymorphisme proprement en redant getName() virtuelle
 

Code :
  1. class A { virtual std::string getName(); };
  2. class B: public A {};
  3. class C{};
  4. A* element = new B;
  5. element->getrName();

`
 
 
Revoir les bases me parait une bonne idée. On ne C-cast pas des objets et surtout pas a partir d'un void*.
 
 


 
Oui, j'ai tenté le void* en désespoir de cause...
 Mais du coup, puisque je veux stocker des objets différents dans une meme liste, je fais comment? Une classe mère dont toutes mes classent héritent? Genre:

Code :
  1. class Mother {};
  2.     class A : public Mother { virtual std::string getName(); };
  3.     class B: public A {};
  4.     class C: public Mother {};
  5.     std::queue<Mother*> maliste;
  6.      B* b = new B;
  7.      C*c = new C
  8.      maliste.push(b); maliste.push(c);


Mais après, pour savoir si ce qui sort d'une maliste.front() implémente B ou pas, je fais comment? Dynamic_cast? Car le is_base_of ne permet pas de le savoir?
 
Sinon,  j'ai des fonctions virtuelles lorsque l'objet doit les implémenter "différemment" (style des calculs, mais le traitement derrière le getname est commun à tout mes objets ayant l'interface).
Du coup c'est effectivement pas propre du tout car l'interface implémente certaines fonctions...  :sweat:  


---------------
I guess my real ennemy is me
Reply

Marsh Posté le 10-10-2011 à 22:42:39    

ton probleme ets mal poser; si tu mets tes objets dans une liste, il doivent avoir unt ruc en commun sinon c'est n'imp.
 
sinon le pattern Visitor pourra aussi aider

Reply

Marsh Posté le 14-10-2011 à 14:57:04    

kray a écrit :

je veux stocker des objets différents dans une meme liste


 
Je dirais qu'a priori c'est bizarre de vouloir faire ça et qu'il y a put-être une erreur de conception en amont. Peux-tu en dire plus sur le contexte ? Comme dit Joël, si tu ranges des objets dans le même conteneur c'est qu'ils se "ressemblent" en quelque chose, sinon pourquoi les mettre ensemble ?
 
 
 

Reply

Marsh Posté le 14-10-2011 à 17:34:01    

Soit une liste de graine, comment séparer le bon grain (qui implémente ton interface) de l'ivraie (qui ne l'implémente pas) ?
 
disclaimer : je suis sans doute rouillé en C++, à prendre avec des pincettes :o
 

Code :
  1. #include <typeinfo>
  2. #include <iostream>
  3. #include <vector>
  4. using namespace std;
  5. class Graine {
  6.     public:
  7.         virtual ~Graine() { }
  8. };
  9. class BonGrain : public Graine {
  10.     public:
  11.         virtual ~BonGrain() { }
  12. };
  13. class Ivraie : public Graine {
  14.     public:
  15.         virtual ~Ivraie() { }
  16. };
  17. void separe(vector<Graine*> &recolte, vector<BonGrain> &grains, vector<Ivraie> &ivraies) {
  18.     for(vector<Graine*>::iterator i(recolte.begin()); i != recolte.end(); ++i) {
  19.         if(BonGrain* bon_grain = dynamic_cast<BonGrain*>(*i)) {
  20.             grains.push_back(*bon_grain);
  21.         }
  22.         else if(Ivraie* ivraie = dynamic_cast<Ivraie*>(*i)) {
  23.             ivraies.push_back(*ivraie);
  24.         }
  25.         else {
  26.             cerr << "Je ne sais pas ce que c'est que cette cochonnerie !\n";
  27.         }
  28.         delete *i;
  29.     }
  30.     recolte.clear();
  31. }
  32. int main() {
  33.     vector<Graine*> recolte;
  34.     vector<BonGrain> grains;
  35.     vector<Ivraie> ivraies;
  36.     recolte.push_back(new BonGrain);
  37.     recolte.push_back(new Ivraie);
  38.     recolte.push_back(new BonGrain);
  39.     separe(recolte, grains, ivraies);
  40.     cout << grains.size() << " bon grains et " << ivraies.size() << " ivraies\n";
  41.     return 0;
  42. }



---------------
Il y a autant d'atomes d'oxygène dans une molécule d'eau que d'étoiles dans le système solaire.
Reply

Marsh Posté le 14-10-2011 à 19:50:04    

if avec dynamic_cast == Visitor qui ne demande qu'a etre implementer :o

Reply

Marsh Posté le 14-10-2011 à 20:10:53    

Joel F a écrit :

if avec dynamic_cast == Visitor qui ne demande qu'a etre implementer :o


 
Yep j'avoue :o (j'espère qu'il cherche bien un truc comme ça et pas une approche plus "réflexivité" )


---------------
Il y a autant d'atomes d'oxygène dans une molécule d'eau que d'étoiles dans le système solaire.
Reply

Marsh Posté le 23-10-2011 à 17:28:19    

En fait, j avais un problème de conception, et je peux effectivement utiliser la méthode de l exemple bon grain / ivraie (ou le pattern visitor )  : tout mes objets peuvent dériver d un objet unique. Par contre je souhaiterai quand meme implémenter des interfaces via queryinterface comme sous windows. Par exemple, un objet voiture ou moto dérive bien d un objet véhicule. Donc la dessus, pb résolu. Mais j aimerai bien une interface human_controlled, ou ia_controlled ou statique par exemple. Et être capable de les utiliser via queryinterface. Je sais que c est possible, j eu utilisé du queryinterface il y à quelques années, mais je sais pas comment c'était implementé derrière.


Message édité par kray le 23-10-2011 à 17:30:07

---------------
I guess my real ennemy is me
Reply

Marsh Posté le 11-11-2011 à 23:54:12    

oui mais reflechi, une voiture EST un vehicule, par contre human_controlled n'est pas un objet. donc ca va pas, ca ne peux pas etre un parent.
par contre tu peux faire heriter vehicule de "controllable" et ensuite mettre des états dans controllable: genre contenir un "controller" qui pourrait par exemple avoir deux types de classes enfant "ia" et "human".
tu vois ?
attention a ne pas heriter là ou ca n'a pas de sens, toujours voir l'heritage comme le verbe "EST".
aussi, si y'a bien un truc que j'ai appris, copier microsoft n'est pas une bonne idée. je voulais le faire aussi quand j'etais jeune mais c'etait parce que j'avais un manque de perspective. normal quand la msdn nous apprend tout au lieu d'un vrai prof d'info...


---------------
http://projets.6mablog.com/
Reply

Marsh Posté le 11-11-2011 à 23:54:12   

Reply

Marsh Posté le 12-11-2011 à 09:13:10    

"EST" c'est l'heritage public, pour l'heritage privé c'ets plutot "ETAIT".

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed