IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

trouver le rang dans la VMT d'une méthode virtuelle


Sujet :

Langage C++

  1. #1
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut trouver le rang dans la VMT d'une méthode virtuelle
    Bonjour,

    je cherchais un code pour obtenir dynamiquement le rang dans la VMT d'une méthode virtuelle, voila la solution que j'ai trouvée qui devrait marcher avec tous les compilateurs/processeurs :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    // CPPVmtRank.cpp : dynamically obtain VMTRank from a pointer to a virtual method
     
    #define __Meth(N) virtual int DummyMethod##N() { return 0x##N; }
    #define __MethX(N) __Meth(N##0) __Meth(N##1) __Meth(N##2) __Meth(N##3) \
    				   __Meth(N##4) __Meth(N##5) __Meth(N##6) __Meth(N##7) \
    				   __Meth(N##8) __Meth(N##9) __Meth(N##A) __Meth(N##B) \
    				   __Meth(N##C) __Meth(N##D) __Meth(N##E) __Meth(N##F)
     
    #define __MethXX(N) __MethX(N##0) __MethX(N##1) __MethX(N##2) __MethX(N##3) \
    				    __MethX(N##4) __MethX(N##5) __MethX(N##6) __MethX(N##7) \
    				    __MethX(N##8) __MethX(N##9) __MethX(N##A) __MethX(N##B) \
    				    __MethX(N##C) __MethX(N##D) __MethX(N##E) __MethX(N##F)
     
    class DummyClass {
    public:
    	__MethXX(0) __MethXX(1) __MethXX(2) __MethXX(3)
    	__MethXX(4) __MethXX(5) __MethXX(6) __MethXX(7)
    	__MethXX(8) __MethXX(9) __MethXX(a) __MethXX(b)
    	__MethXX(c) __MethXX(d) __MethXX(e) __MethXX(f)
            ///4096 DummyMethods
    };
     
    DummyClass dummyObj;
     
    class A {
    public:
    	virtual void Meth0();
    	virtual void Meth1();
    	virtual void Meth2();
    	virtual void Meth3();
    	virtual void Meth4();
    	virtual void Meth5();
    	virtual void Meth6();
    };
     
    template <typename T> int GetVMTRank(T t) {
    	int (DummyClass::*methPtr)();
    	*(void**)&methPtr = *(void**)&t;
    	return (dummyObj.*methPtr)();
    }
     
    int main() {
    	int Meth0_VMTRank = GetVMTRank(&A::Meth0);
    	int Meth6_VMTRank = GetVMTRank(&A::Meth6);
    }
    je pense que le seul truc qui peut faire crasher c'est si le compilateur s'amuse à ne pas mettre dans la VMT les méthodes dans l'ordre de leur déclaration,
    dans ce cas il est possible de créer une DummyClass par DummyMethod (DummyClass9 héritant de DummyClass8) pour obliger le compilateur à mettre les DummyMethod dans l'ordre.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    une seule question : pourquoi ?
    Un &mymethod - this serait pas une info suffisante ? Si tenté qu'elle soit d'une quelconque utilité.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut
    salut,

    c'est gentil de t'intéresser à mon message

    C'est peu intuitif mais en fait il existe deux types de pointeurs de méthode :
    - les pointeurs de méthode non virtuelle qui sont l'adresse du début de la méthode
    - les pointeurs de méthode virtuelle qui sont l'adresse d'un bout de code qui lit la VMT de l'objet (sur lequel on fait l'appel) et redirige vers la "vraie méthode"

    ainsi, si mymethodPtr est un pointeur de méthode virtuelle, alors
    n'enverra pas forcément vers le même code que (si obj2 surcharge la méthode virtuelle correspondante), c'est cette subtilité que j'exploite à fond dans mon code, où j'appelle mymethodPtr sur un objet qui n'implémente même pas la méthode vers laquelle pointe mymethodPtr..

    pour finir, avec des &maClasse::mymethod on n'a aucune chance d'obtenir l'adresse de la case de la VMT de la classe qui pointe vers mymethod. Cependant je suis d'accord que le compilateur n'a aucune excuse pour ne pas proposer de syntaxe simple le permettant.

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par acx01b Voir le message
    salut,

    c'est gentil de t'intéresser à mon message

    C'est peu intuitif mais en fait il existe deux types de pointeurs de méthode :
    - les pointeurs de méthode non virtuelle qui sont l'adresse du début de la méthode
    - les pointeurs de méthode virtuelle qui sont l'adresse d'un bout de code qui lit la VMT de l'objet (sur lequel on fait l'appel) et redirige vers la "vraie méthode"
    Si ce n'est que la table de fonctions virutelles se trouve bel et bien dans ta classe, mais qu'il n'y a que ca dans ta classes.

    Qu'elles soient virtuelles ou non, les fonctions membres sont gérées exactement comme des fonctions libres au niveau du binaire exécutable, à ceci près que leur premier argument est this (le pointeur sur l'objet au départ duquel la fonction est appelée) et du "mangling" (la décoration qui permet de retirer tout ambiguité quant à la fonction appelée).

    Les fonctions membres virtuelles passent effectivement par une indirection supplémentaire (la table de fonctions virutelles qui contient l'adresse de la fonction à exécuter) mais il n'y a que les fonctions virutelles qui le fassent

    ainsi, si mymethodPtr est un pointeur de méthode virtuelle, alors
    n'enverra pas forcément vers le même code que (si obj2 surcharge la méthode virtuelle correspondante), c'est cette subtilité que j'exploite à fond dans mon code, où j'appelle mymethodPtr sur un objet qui ne n'implémente même pas !
    Que veux tu dire par "n'enverra pas forcément le même code

    Au niveau du compilateur, une fonction est exécutée ou non et renvoie une valeur ou non. Il n'y a rien d'autre que cela

    Au niveau des pointeurs de fonctions, une fonction virtuelle est déclarée dans la classe de base ou non.

    A partir de là, tu peux (ou non) l'utiliser comme un pointeur de fonction membre de l'objet de base, ou non. Point barre

    Il n'y a que les fonctions qui ne sont pas définies dans la classe de base qui ne pourront pas être utilisées comme un pointeur de fonction membre l'objet de base mais qui devront être utilisées comme des pointeur de fonctions membres du type dérivé
    pour finir, avec des &maClasse::mymethod on n'a aucune chance d'obtenir l'adresse de la case de la VMT de la classe qui pointe vers mymethod. Cependant je suis d'accord que le compilateur n'a aucune excuse pour ne pas proposer de syntaxe simple le permettant.
    Mais, comme Bousk, j'ai envie de dire "pourquoi"

    Tu n'as jamais besoin d'accéder directement à la table des fonctions virtuelles.

    Ce n'est qu'un système de "popote interne" qui permet de mettre en place un besoin particulier qui est l'adaptation potentielle d'un comportement en fonction du type réel de l'objet au départ duquel on appelle le dit comportement.

    Tu peux savoir que l'indirection supplémentaire fera qu'il faut "un peu plus de temps" (on le compte en cycles d'horloges, là ) pour appeler la fonction, mais ca s'arrête là

    Essayer de savoir quel est le rang de ta fonction virtuelle dans la table revient à essayer de voir dans le cylindre d'un moteur ce qui se passe lorsque l’étincelle vient enflammer l'essence: il vaut mieux le faire par simulation dont on peut ralentir l'exécution
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Citation Envoyé par acx01b Voir le message
    ainsi, si mymethodPtr est un pointeur de méthode virtuelle, alors
    n'enverra pas forcément vers le même code que (si obj2 surcharge la méthode virtuelle correspondante)
    Que veux tu dire par "n'enverra pas forcément le même code
    je veux dire que si mymethodPtr pointe vers la première méthode virtuelle d'une classe, alors mymethodPtr sera l'adresse du code assembleur suivant (en win32) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    B::`vcall'{0}':
    00B5D5E0  mov         eax,dword ptr [ecx]  
    00B5D5E2  jmp         dword ptr [eax]
    ainsi, suivant l'objet lequel on appelle le pointeur de méthode, la vrai méthode exécutée ne sera pas forcément la même !

    la sémantique d'un pointeur de méthode virtuelle ou non n'est pas donc pas exactement la même : dans un cas c'est "appeler la méthode à l'adresse X sur l'objet Y", et dans l'autre c'est "appeler la méthode au rang N de la VMT de l'objet Y sur l'objet Y"

    Pour finir, voici un screenshot qui montre que regarder la VMT de ses objets est loin d'être idiot quand on cherche à résoudre un bug dû à un objet invalide :



    En regardant la VMT de l'objet passé en paramètre de "uneFonction" on voit tout de suite que c'est un A et non un B.

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    A moins que tu ne t'y prennes très mal

    N'aurais tu, par hasard, pas oublié que qui dit fonction virtuel dit héritage public et que qui dit héritage public dit sémantique d'entité, donc, objet non copiables et non affectables par nature

    Si tu veux appeler une fonction membre par callback, et que cette fonction n'est pas statique, il te faut forcément un objet au départ duquel invoquer la fonction en question.

    Si tu transmets l'objet de manière "classique" par copie, tu ne peux pas profiter du polymorphisme car le paramètre transmis lorsque tu passes un objet du type dérivé correspond au "sous ensemble" représenté par le type de base, et il est donc logique que tu observes le comportement propre au type de base

    Mais, si tu prends la précaution de rendre tes classes de base non copiables et non affectables (*), le compilateur te préviendra tout de suite que tu fais une erreur, t'obligeant à transmettre ton argument sous la forme d'un pointeur ou d'une référence.

    Et, justement, si tu transmets ton paramètre sous la forme d'un pointeur ou d'une référence, tu peux profiter du polymorphisme, et tu n'as donc pas besoin d'accéder à la table de fonctions virtuelles

    (*) Pour rendre les classes non copiables et non affectables, il y a trois solutions, par préférence:

    - La solution C++11 qui consiste à déclarer l'opérateur d'affectation et le constructeur de copie comme delete:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class MyBase{
        public:
            MyBase(MyBase const &) = delete;
            MyBase& operator=(MyBase const &) = delete;
    };
    - La solution boost::noncopyable qui consiste à faire hériter de manière privée ta classe de base de cette classe fournie par boost
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class MyBase : private boost::noncopyable{
        public:
    };
    - La solution utilisée depuis la nuit des temps qui consiste à déclarer sans les définir les opérateur d'affectation et constructeur par copie de la classe de base dans l'accessibilité privée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class MyBase{
        public:
            /* ... */
        private:
            /*!!! NE SUROUT PAS FOURNIR D'IMPLEMENTATION !!! */
            MyBase(MyBase const &) ;
            MyBase& operator=(MyBase const &) ;
    };
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par acx01b Voir le message
    j
    En regardant la VMT de l'objet passé en paramètre de "uneFonction" on voit tout de suite que c'est un A et non un B.
    Parce que tu le caste explicitement en B!!!

    La règle suivie par C et par C++ est la même ici :
    trust the developer, even if it is bullshit
    "

    Tu dis explicitement que ton pointeur sur A doit être considéré comme un pointeur sur B.

    Or, A et B sont deux classes totalement différentes entre lesquelles il n'y a strictement aucune relation (et surtout pas de relation d'héritage)

    Comment veux tu que le compilateur sache que tu n'as pas une excellente raison de vouloir faire passer ton A pour un B

    Nous ne sommes pas en java, ici, il n'y a pas d'héritage caché avec une quelconque classe Object (ou quel que soit son nom réel) : nous sommes en C++ ou la règle est "vous ne payez que pour ce que vous utilisez"

    Si tu veux pouvoir faire passer ton objet de type A (ou, dans le cas présent, un pointeur vers ton objet de type A) comme étant (un pointeur vers) un objet de type B, il faut que A hérite publiquement de B, et, à ce moment là, le transtypage devient inutile tout simplement parce que ton A... EST un B .

    Mais, encore faut-il que cela ait du sens au niveau du LSP (Liskov Substitution Principle, ou, si tu préfères, le principe de substitution de Liskov)... Mais c'est un autre problème

    Si cela n'a pas de sens de faire hériter A de B, tu dois te tourner vers une alternative :

    Soit tu surcharge simplement la fonction pour qu'une des version prenne un A* et que l'autre prenne un B*, sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void uneFonction(A* a){
     
    }
    void uneFonction(B* b){
     
    }
    soit, si tu es certain que tes deux classes exposent des fonctions publiques identiques, tu utilise une fonction template sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template <typename T>
    void uneFonction(T * t){
       /* !!! Tout type transmis à cette fonction DOIT exposer une fonction
        * membre publique Meth !!!
        */
       t->Meth();
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  8. #8
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut
    tu es hors sujet ...
    tu me donnes un cours de C++ alors que ce n'est pas du tout le propos ...
    merci quand même

  9. #9
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par acx01b Voir le message
    tu es hors sujet ...
    tu me donnes un cours de C++ alors que ce n'est pas du tout le propos ...
    merci quand même
    Je ne suis pas du tout hors sujet, contrairement à ce que tu pourrais le croire.

    Je me rend compte que, partant sur de mauvaises bases, tu te poses une question qui n'a, simplement, aucun sens et que, en gros, tu sembles te créer des problèmes pour avoir le plaisir de les résoudre.

    Je tentes donc de t'expliquer pourquoi cela n'a aucun sens de se poser ce genre de question et comment y remédier selon le principe du "donnes un poisson à quelqu'un..." (tu connais la suite ).

    Maintenant, je pars du principe que ceux qui viennent sur le forum espèrent s'améliorer et évoluer dans leur compréhension de ce merveilleux langage qu'est le C++ et qu'il seront d'accord de se remettre un tant soit peu en question quand ils font une boulette manifeste !

    Peut etre n'est-ce tout simplement pas ton cas Mais, dans ces conditions, je ne peux pas grand chose pour toi

    En attendant, ceux qui liront cette discussion se feront leur propre idée
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  10. #10
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut
    concernant l'utilité de connaître le rang d'une méthode dans la VMT, l'idée est simple : ça permet de créer dynamiquement des types, d'implémenter toute sorte de hacks, plus ou moins utiles.
    Il faut voir que la possibilité de créer dynamiquement des types c'est plus ou moins l'aboutissement de la réflexion, et en C++ tout le monde sait qu'il n'y a pas de réflexion sauf si on l'implémente à la main, d'où mon code.

    Si ça ne vous convainc pas, imaginez que vous disposez d'une lib C++ compilée (par exemple Ogre3D mais sans les sources), et que vous souhaitez ajouter un bout de code au début d'une méthode, sauf que cette méthode est virtuelle et que son adresse est dans la VMT d'un objet instancié par la lib, hé bien pourquoi ne pas simplement pirater la VMT de l'objet, remplacer la méthode par la votre (qui bien sûr après avoir fait des choses rappelle la méthode originale), et voila, vous avez ajouté un bout de code au début d'une méthode où on ne vous permettait pas de le faire, et ce d'une manière assez élégante.

  11. #11
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Quand on fait un cast aussi bourrin, faut pas être surpris du résultat...
    Btw, ça ressemble plus à du template qu'à de l'héritage ou quoi que ce soit de cet ordre.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par acx01b Voir le message
    concernant l'utilité de connaître le rang d'une méthode dans la VMT, l'idée est simple : ça permet de créer dynamiquement des types, d'implémenter toute sorte de hacks, plus ou moins utiles.
    C'est bien là le problème : tu parles d'implémenter des hacks, autrement dit, des emplâtre sur une jambe de bois pour essayer de faire avec des erreurs de développements, plutôt que d'essayer de résoudre les dites erreurs
    Il faut voir que la possibilité de créer dynamiquement des types
    Et que dirais tu de les créer à la compilation sans avoir à dupliquer ton code

    (note que alexandrescu qui est le père du projet est un membre du comité de normalisation du C++: il sait de quoi il parle )
    c'est plus ou moins l'aboutissement de la réflexion, et en C++ tout le monde sait qu'il n'y a pas de réflexion sauf si on l'implémente à la main, d'où mon code.
    Sur la première page de recherche de notre ami à tous, j'ai trouvé en moins de cinq minutes ==>ceci<==, c'est bizarre

    Je te l'accorde, la réflexion n'est pas en soi quelque chose d'aisé à implémenter, mais je t'avoues n'avoir jamais eu besoin d'elle depuis que je développe

    Dans le pire des cas, je passe par des langages différents qui s'interfacent parfaitement avec C++, comm python grace à boost::python ou encore lua

    C'est très beau de souffrir du NIH, mais, si c'est pour faire moins bien ce que des frameworks de qualité font de manière exemplaire, est-ce que cela vaut le coup (le cout)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  13. #13
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut
    j'ai regardé un peu cpgf,
    je n'ai pas regardé le code source de leur ._method(...) dont ils parlent sur
    http://www.cpgf.org/document/reflect...reflect-method

    mais sur
    http://www.cpgf.org/document/reflect...ng-meta-method
    ils n'ont pas l'air de dire qu'ils font la différence entre méthode virtuelle et méthode non virtuelle, et encore moins qu'ils peuvent dire le rang dans la VMT d'une certaine méthode virtuelle !

    le code source de class GMetaMethod confirme qu'ils n'ont pas de "bool isVirtual" ni de "int VMTRank"

    tu crois que ça les intéressera si je leur envoie un mail ?

  14. #14
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par acx01b Voir le message
    ce entre méthode virtuelle et méthode non virtuelle, et encore moins qu'ils peuvent dire le rang dans la VMT d'une certaine méthode virtuelle !
    Parce qu'il n'y a aucune raison de vouloir disposer du rang de la fonction dans la table des fonctions virtuelle, tout simplement

    Une fonction virtuelle n'a de sens que lorsque tu es en présence d'une relation d'héritage public.

    A partir du moment où tu as cette relation, et uniquement si tu as cette relation, la virtualité d'une fonction permet d'en adapter le comportement pour les types dérivés qui nécessitent une adaptation.

    Si le type que tu essayes de transmettre en paramètre n'est pas un type qui intervient dans la hiérarchie de classe correspondant au paramètre attendu par ta fonction, il ne faut purement et simplement pas essayer de transtyper ton objet dans le type attendu, ca va te pêter à la figure de manière systématique !

    Le problème que tu essayes de résoudre revient à celui auquel tu serais confronté si tu demandais à un aveugle de te miner un terrain que tu espères pouvoir traverser les yeux bandés!

    le code source de class GMetaMethod confirme qu'ils n'ont pas de "bool isVirtual" ni de "int VMTRank"
    Parce qu'on n'en a simplement jamais besoin!

    Le fait qu'une fonction soit virtuelle n'est jamais qu'un "détail d'implémentation" dont on n'a absolument pas besoin de s'inquiéter à partir du moment où l'on respecte les règles relatives aux objets ayant des comportements polymorphes, et relatives à l'héritage public en particulier

    Il peut être intéressant, dans certaines circonstances, de s'assurer qu'un objet a bel et bien des comportements polymorphes, mais cela s'arrête là, et C++11 est d'ailleurs arrivé avec un trait qui permet de le déterminer
    tu crois que ça les intéressera si je leur envoie un mail ?
    Tu peux toujours leur envoyer le mail, mais ne t'étonnes pas s'ils te font une réponse similaire
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  15. #15
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut
    Parce qu'on n'en a simplement jamais besoin!
    Ben on en a besoin clairement quand on crée dynamiquement des types C++,

    ou bien, toujours dans le cadre du C++ avec réflexion, on peut aussi l'utiliser pour gérer des histoires de versionning de dll : vérifier que la VMT d'une classe n'a été augmentée qu'à la fin, que personne n'a rajouté de méthode au milieu, car sinon il faut compiler les différentes dll qui utilisent la classe.

    Pour l'intérop entre un langage et C++ c'est également clairement intéressant,

    ou encore par exemple si tu veux exporter en Python les deux méthodes A::Method et B::Method pour pouvoir explicitement appeler A::Method sur un objet B (B hérite de A..)

  16. #16
    Membre à l'essai
    Inscrit en
    Octobre 2013
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Octobre 2013
    Messages : 2
    Points : 19
    Points
    19
    Par défaut
    Hi, I'm the author of cpgf library.
    With the help of Google translate, I understood this thread a little bit.

    You are totally correct. GMetaMethod doesn't need to know whether a method is virtual or not. GMetaMethod uses member function pointer to invoke the method. A member function pointer may,
    1, points to the real code address, for non-virtual function,
    2, or some structure which holds the VTable offset, and the compiler generates the redirect code when invoking the method.
    C++ compiler does all the magic under function pointer.

    If you need to know if a method is virtual, there is is_polymorphic type trait in both C++ 11 and Boost.

  17. #17
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Hello, welcome to this forum

    As you can see, this forum is dedicated to French users, so I will translate your message for everyone to understand it.

    We're happy (and a little surprised) that you've seen this discussion and we hope you will feel free to respond if needed.
    I'll be happy to translate your interventions

    (traduction : Comme vous pouvez le voir, ce forum est spécifique au utilisateurs francophone, je vais donc traduire votre message pour m'assurer que tout le monde le comprendra

    Nous sommes contents (et un peu surpis) que vous ayez vu cette discussion et nous espérons que vous vous sentirez libre de répondre en cas de besoins.

    Je me ferai un plaisir de traduire vos interventions
    Citation Envoyé par wqking Voir le message
    Hi, I'm the author of cpgf library.
    With the help of Google translate, I understood this thread a little bit.

    You are totally correct. GMetaMethod doesn't need to know whether a method is virtual or not. GMetaMethod uses member function pointer to invoke the method. A member function pointer may,
    1, points to the real code address, for non-virtual function,
    2, or some structure which holds the VTable offset, and the compiler generates the redirect code when invoking the method.
    C++ compiler does all the magic under function pointer.

    If you need to know if a method is virtual, there is is_polymorphic type trait in both C++ 11 and Boost.
    traduction
    Citation Envoyé par wqking Voir le message
    Salut, je suis l'auteur de la bibliothèque CPGF.
    J'ai plus ou moins compris cette discussion grâce à l'aide de Google translate.

    Vous avez totalement raison. GMetaMethod n'a pas besoin de savoir si une méthode est virtuelle ou non. GMetaMethod utilise un pointeur sur fonction membre pour invoquer la méthode. Un pointeur sur fonction membre peut,
    1, pointer sur l'adresse réelle du code, pour les fonctions non virtuelles
    2, pointer vers l'indice de la VTable, et le compilateur génère la redirection lorsque la méthode est invoquée
    Le compilateur C++ s'occupe du reste

    Si vous avez besoin de savoir si une méthode est virtuelle, vous disposez du trait is_polymorphic en C++11 et dans boost.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  18. #18
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut
    Citation Envoyé par acx01b Voir le message
    je pense que le seul truc qui peut faire crasher c'est si le compilateur s'amuse à ne pas mettre dans la VMT les méthodes dans l'ordre de leur déclaration,
    dans ce cas il est possible de créer une DummyClass par DummyMethod (DummyClass9 héritant de DummyClass8) pour obliger le compilateur à mettre les DummyMethod dans l'ordre.
    Je suis un peu vexé, car j'ai découvert que si celui qui a déjà regardé du code assembleur sait que sur les processeurs "dits normaux" il existe au moins 3 principaux callstyle pour les méthodes : __thiscall, __stdcall, __clrcall (et d'autres peu utilisés),
    qu'il sait également que ces trois principaux callstyle ont le bon goût de placer l'argument 'this' dans ecx (resp. rcx sur x64), qu'il en déduit que pour les méthodes à 0 arguments, ces callstyle sont similaires,

    il y a une petite subtilité que le premier clampin venu (dont je fais partie) n'a pas remarquée : le protocole d'appel des pointeurs de méthode !
    Hè non, vous l'aurez compris, on ne passe pas toujours 'this' dans ecx quand on appelle un pointeur de méthode.. Parfois on le passe dans la pile ! Satané C++ et ses milliards de subtilités...
    Donc mon code ne marche que si la méthode virtuelle dont on souhaite connaître le VMTrank a le même callstyle que les méthodes de DummyClass.
    Si on veut être généraliste, on doit faire une DummyClass par callstyle, et récupérer le callstyle avec un template, de préférence C++11 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    enum TheCallStyles {
       CallStyle_thiscall, CallStyle_stdcall, CallStyle_clrcall
    };
    template <class U, typename T, typename... Args> TheCallStyles GetCallStyle(T (__thiscall U::*methPtr)(Args)) { return CallStyle_thiscall; }
     
    template <class U, typename T, typename... Args> TheCallStyles GetCallStyle(T (__stdcall U::*methPtr)(Args)) { return CallStyle_stdcall; }
     
    template <class U, typename T, typename... Args> TheCallStyles GetCallStyle(T (__clrcall U::*methPtr)(Args)) { return CallStyle_clrcall; }
    (non testé je n'ai pas de compilateur C++11..)

    Au pire, si on n'aime pas le C++11, on peut faire un template pour les méthodes à 0 argument, un autre pour les méthodes à 1 argument, à 2, 3,4, etc.

  19. #19
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut
    Citation Envoyé par wqking Voir le message
    Hi, I'm the author of cpgf library.
    With the help of Google translate, I understood this thread a little bit.

    You are totally correct. GMetaMethod doesn't need to know whether a method is virtual or not.
    Hi, thank you to participate to that discussion.

    I have a few arguments to arg that it is useful to known VMTrank in a metadata library :
    - you can dynamically override some methods, do some tricks (some hacks) at runtime that you couldn't do otherwise, you can insert some code at the beginning of a method without using asm/opcodes.
    - you can dynamically create C++ types, for example if you have a runtime compiler, or any script langage that can interact with C++
    - you can insert some tracing code, you can call a debugger without adding any _asm{int 3} opcode.

    I think you don't agree with my arguments, so there is my question :
    what is useful with a C++ meta-data library ? You can use it to write serialization code, what can you do else ?

    j'ai plusieurs arguments pour défendre l'idée qu'il est utile de connaître le VMTrank d'une méthode dans une libraire de méta-données :
    - overrider dynamiquement une méthode,
    - créer dynamiquement de nouveaux types C++, par exemple si on dispose d'un compilateur au runtime, ou d'un langage de script qui peut intéragir avec le C++,
    - insérer du code de tracing, appeler un débuggueur sans insérer d'opcode _asm{int 3}

    Je pense que vous n'êtes pas d'accord avec mes arguments, donc voila ma question : à quoi peut être utile une librairie de méta données ? On peut l'utiliser pour faire du code de sérialisation automatique, et à part ça ?
    Merci.

  20. #20
    Membre à l'essai
    Inscrit en
    Octobre 2013
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Octobre 2013
    Messages : 2
    Points : 19
    Points
    19
    Par défaut
    Citation Envoyé par acx01b Voir le message
    Hi, thank you to participate to that discussion.

    I have a few arguments to arg that it is useful to known VMTrank in a metadata library :
    - you can dynamically override some methods, do some tricks (some hacks) at runtime that you couldn't do otherwise, you can insert some code at the beginning of a method without using asm/opcodes.
    - you can dynamically create C++ types, for example if you have a runtime compiler, or any script langage that can interact with C++
    - you can insert some tracing code, you can call a debugger without adding any _asm{int 3} opcode.

    I think you don't agree with my arguments, so there is my question :
    what is useful with a C++ meta-data library ? You can use it to write serialization code, what can you do else ?

    Merci.
    Hi,

    All your points look more like some debug/hack features rather than normal C++ features. It's possible to hack the member function pointer to get the VTable index, but it's a hack. It's not standard or portable, and heavily depends on C++ compiler internal mechanism.

    For your question, beside serialization, script binding is another big feature in a meta data library. Now cpgf supports script binding in Lua, Python, Google V8, and Mozilla SpiderMonkey. So with a single meta data, we can use the meta data in Lua, Python and JavaScript. There are pre-made meta data in cpgf library, such as Box2D, Irrlicht, OpenGL, etc.

    Also, meta data is great if you are making property editor. A property editor can read and write values via meta data.


Discussions similaires

  1. [XL-2007] Trouver la colonne dans laquelle se trouve une valeur donnée
    Par Accessifiante dans le forum Excel
    Réponses: 7
    Dernier message: 04/10/2014, 08h45
  2. Réponses: 2
    Dernier message: 01/02/2013, 13h25
  3. Trouver un nombre dans un tableau avec une fonction
    Par neufrdb dans le forum Collection et Stream
    Réponses: 6
    Dernier message: 27/03/2011, 16h33
  4. Réponses: 3
    Dernier message: 02/03/2009, 12h31
  5. Réponses: 2
    Dernier message: 21/07/2006, 06h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo