(désolé s'il y a des fautes de frappes, j'ai pas compilé le code, c'est
l'idée qui compte)
Dans ce cas, quelle fonction est appelée : A::f ou B::f ?
J'ai cherché dans la norme sans rien trouver de bien convainquant.
Le 10.3.12
Explicit qualification with the scope operator (5.1) suppresses the
virtual call mechanism.
Me fait penser que comme on a explicité A::f, il n'y aura pas appel
virtuel, mais j'avoue ne pas savoir si ce passage est suffisant ou même
approprié.
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Lahsen
Trace la fonction f dans A et dans B et puis appelle la par un pointeur et tu sera.
Bonjour,
Soit le cas suivant :
struct A { virtual void f(); };
void A::f() { cout << " f de A est appelé" << endl; }
struct B : A { virtual void f(); }
void B::f() { cout << " f de B est appelé" << endl; }
typedef void (A::*FctPtr)();
FctPtr fct = &A::f;
int main() { A *b = new B; b->*fct(); }
C'est quoi *fct()??? Il faut peut être la déclarer avant de l'appeler!!!
(désolé s'il y a des fautes de frappes, j'ai pas compilé le code, c'est l'idée qui compte)
Dans ce cas, quelle fonction est appelée : A::f ou B::f ?
J'ai cherché dans la norme sans rien trouver de bien convainquant. Le 10.3.12 Explicit qualification with the scope operator (5.1) suppresses the virtual call mechanism.
Me fait penser que comme on a explicité A::f, il n'y aura pas appel virtuel, mais j'avoue ne pas savoir si ce passage est suffisant ou même approprié.
Merci,
Trace la fonction f dans A et dans B et puis appelle la par un pointeur
et tu sera.
Bonjour,
Soit le cas suivant :
struct A
{
virtual void f();
};
void A::f()
{
cout << " f de A est appelé" << endl;
}
struct B : A
{
virtual void f();
}
void B::f()
{
cout << " f de B est appelé" << endl;
}
typedef void (A::*FctPtr)();
FctPtr fct = &A::f;
int main()
{
A *b = new B;
b->*fct();
}
C'est quoi *fct()??? Il faut peut être la déclarer avant de l'appeler!!!
(désolé s'il y a des fautes de frappes, j'ai pas compilé le code, c'est
l'idée qui compte)
Dans ce cas, quelle fonction est appelée : A::f ou B::f ?
J'ai cherché dans la norme sans rien trouver de bien convainquant.
Le 10.3.12
Explicit qualification with the scope operator (5.1) suppresses the
virtual call mechanism.
Me fait penser que comme on a explicité A::f, il n'y aura pas appel
virtuel, mais j'avoue ne pas savoir si ce passage est suffisant ou même
approprié.
Trace la fonction f dans A et dans B et puis appelle la par un pointeur et tu sera.
Bonjour,
Soit le cas suivant :
struct A { virtual void f(); };
void A::f() { cout << " f de A est appelé" << endl; }
struct B : A { virtual void f(); }
void B::f() { cout << " f de B est appelé" << endl; }
typedef void (A::*FctPtr)();
FctPtr fct = &A::f;
int main() { A *b = new B; b->*fct(); }
C'est quoi *fct()??? Il faut peut être la déclarer avant de l'appeler!!!
(désolé s'il y a des fautes de frappes, j'ai pas compilé le code, c'est l'idée qui compte)
Dans ce cas, quelle fonction est appelée : A::f ou B::f ?
J'ai cherché dans la norme sans rien trouver de bien convainquant. Le 10.3.12 Explicit qualification with the scope operator (5.1) suppresses the virtual call mechanism.
Me fait penser que comme on a explicité A::f, il n'y aura pas appel virtuel, mais j'avoue ne pas savoir si ce passage est suffisant ou même approprié.
Merci,
Jean-Marc Bourguet
Loïc Joly writes:
Bonjour,
Soit le cas suivant :
struct A { virtual void f(); };
struct B : A { virtual void f(); }
;
typedef void (A::*FctPtr)();
FctPtr fct = &A::f;
int main() { A *b = new B; b->*fct(); (b->*fct)();
}
(désolé s'il y a des fautes de frappes, j'ai pas compilé le code, c'est l'idée qui compte)
Dans ce cas, quelle fonction est appelée : A::f ou B::f ?
B::f -- d'après mes souvenirs et mes compilateurs -- mais j'ai trouvé de référence.
J'ai cherché dans la norme sans rien trouver de bien convainquant. Le 10.3.12 Explicit qualification with the scope operator (5.1) suppresses the virtual call mechanism.
Me fait penser que comme on a explicité A::f, il n'y aura pas appel virtuel, mais j'avoue ne pas savoir si ce passage est suffisant ou même approprié.
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
int main()
{
A *b = new B;
b->*fct();
(b->*fct)();
}
(désolé s'il y a des fautes de frappes, j'ai pas compilé le code, c'est
l'idée qui compte)
Dans ce cas, quelle fonction est appelée : A::f ou B::f ?
B::f -- d'après mes souvenirs et mes compilateurs -- mais j'ai trouvé de
référence.
J'ai cherché dans la norme sans rien trouver de bien convainquant. Le
10.3.12 Explicit qualification with the scope operator (5.1) suppresses
the virtual call mechanism.
Me fait penser que comme on a explicité A::f, il n'y aura pas appel
virtuel, mais j'avoue ne pas savoir si ce passage est suffisant ou même
approprié.
A+
--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
int main() { A *b = new B; b->*fct(); (b->*fct)();
}
(désolé s'il y a des fautes de frappes, j'ai pas compilé le code, c'est l'idée qui compte)
Dans ce cas, quelle fonction est appelée : A::f ou B::f ?
B::f -- d'après mes souvenirs et mes compilateurs -- mais j'ai trouvé de référence.
J'ai cherché dans la norme sans rien trouver de bien convainquant. Le 10.3.12 Explicit qualification with the scope operator (5.1) suppresses the virtual call mechanism.
Me fait penser que comme on a explicité A::f, il n'y aura pas appel virtuel, mais j'avoue ne pas savoir si ce passage est suffisant ou même approprié.
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
Jean-Marc Bourguet
Lahsen writes:
Trace la fonction f dans A et dans B et puis appelle la par un pointeur et tu sera.
Loïc cherche peut-être quelque chose de plus sûr que le comportement de son compilateur (et puis il a écrit qu'il n'en avait pas sous la main)
FctPtr fct = &A::f;
b->*fct();
(b->*fct)();
C'est quoi *fct()??? Il faut peut être la déclarer avant de l'appeler!!!
J'ai laissé sa définition et corrigé son utilisation.
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
Lahsen <lahsenba@free.fr> writes:
Trace la fonction f dans A et dans B et puis appelle la par un pointeur
et tu sera.
Loïc cherche peut-être quelque chose de plus sûr que le comportement de son
compilateur (et puis il a écrit qu'il n'en avait pas sous la main)
FctPtr fct = &A::f;
b->*fct();
(b->*fct)();
C'est quoi *fct()??? Il faut peut être la déclarer avant de l'appeler!!!
J'ai laissé sa définition et corrigé son utilisation.
A+
--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Trace la fonction f dans A et dans B et puis appelle la par un pointeur et tu sera.
Loïc cherche peut-être quelque chose de plus sûr que le comportement de son compilateur (et puis il a écrit qu'il n'en avait pas sous la main)
FctPtr fct = &A::f;
b->*fct();
(b->*fct)();
C'est quoi *fct()??? Il faut peut être la déclarer avant de l'appeler!!!
J'ai laissé sa définition et corrigé son utilisation.
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
Michel Decima
typedef void (A::*FctPtr)();
FctPtr fct = &A::f;
int main() { A *b = new B; b->*fct(); }
C'est quoi *fct()???
C'est l'appel de la fonction via un pointeur sur fonction membre. D'ailleurs mon g++ me dit qu'il faut des parentheses supplementaires, comme ceci: (b->*fct)();
Il faut peut être la déclarer avant de l'appeler!!!
C'est fait sur la ligne qui precede le main()
typedef void (A::*FctPtr)();
FctPtr fct = &A::f;
int main()
{
A *b = new B;
b->*fct();
}
C'est quoi *fct()???
C'est l'appel de la fonction via un pointeur sur fonction membre.
D'ailleurs mon g++ me dit qu'il faut des parentheses supplementaires,
comme ceci: (b->*fct)();
Il faut peut être la déclarer avant de l'appeler!!!
C'est l'appel de la fonction via un pointeur sur fonction membre. D'ailleurs mon g++ me dit qu'il faut des parentheses supplementaires, comme ceci: (b->*fct)();
Il faut peut être la déclarer avant de l'appeler!!!
C'est fait sur la ligne qui precede le main()
James Kanze
Loïc Joly wrote:
Soit le cas suivant :
struct A { virtual void f(); };
struct B : A { virtual void f(); }
typedef void (A::*FctPtr)();
FctPtr fct = &A::f;
int main() { A *b = new B; b->*fct();
Il y manque des parenthèses : ce que tu a écris est l'équivalent de « b->*(fct()) », c-à-d qu'il appellerait une fonction libre fct, qui doit renvoyer un pointeur à membre, et puis accéderait au membre désigné (pour ne rien faire avec lui) de l'objet désigné par b.
Essaie « (b->*fct)() ».
}
(désolé s'il y a des fautes de frappes, j'ai pas compilé le code, c'est l'idée qui compte)
Dans ce cas, quelle fonction est appelée : A::f ou B::f ?
B::f ?
J'ai cherché dans la norme sans rien trouver de bien convainquant. Le 10.3.12 Explicit qualification with the scope operator (5.1) suppresses the virtual call mechanism.
§10.3/13 (au moins dans la version de travail le plus récente) ne parle que vaguement des appels directs. Où il faut chercher, c'est dans la section 5, sur la signification des expressions. Surtout §5.2.2/1 (vers la fin) : « The function called in a member function call is normally selected according to the static type of the object expression (clause 10), but if that function is virtual and is not specified using a qualified id then the function actually called will be the final overrider (10.3) of the selected function in the dynamic type of the object expression ». Or, ici, la fonction est spécifiée au moyen d'un pointeur à membre, qui n'est pas une « qualified id ». Donc, si la fonction est virtuelle, la fonction réelement appelée serait la supplantation finale de la fonction choisie dans le type dynamique de l'expression designant l'objet.
Si tu as l'occasion de régarder dans l'ARM, Stroustrup y propose une implémentation possible, qui correspond d'assez près à celle utiliser dans CFront (et encore dans VC++, je crois) : un pointeur à une function membre est en fait une structure, qui contient l'information si la fonction est virtuelle ou non, et le cas échéant, soi son adresse réele, soi l'indice de son entrée dans le vtable. (L'autre implémentation que je connais, c'est de générer un trampoline, c-à-d une fonction sans nom qui ressemble à une fonction membre non-virtuelle de A, et qui appelle la fonction en question, et de mettre l'adresse du trampoline dans le pointeur. C'est celui qui sert aujourd'hui dans g++ et dans Sun CC.)
Me fait penser que comme on a explicité A::f, il n'y aura pas appel virtuel, mais j'avoue ne pas savoir si ce passage est suffisant ou même approprié.
La suppression de la virtualité dépend de la syntaxe de l'appel. Si la fonction est désignée par une expression qualifiée, l'appel n'est jamais virtuelle. Sinon, l'appel est virtuel si la fonction appelée est déclarée virtuelle.
En passant, c'est intéressant à noter qu'avec des pointeurs au membre, on a même une forme assez restreinte de la virtualité pour les données :
struct A {} ; struct B : A { int i ; } ;
int A::*pi = static_cast< int A::* >( &B::i ) ;
void f( A* p ) { std::cout << p->*pi ; }
C'est légal, et ça marche, dans la mesure où l'objet désigné par p a réelement un type dynamique B (ou quelque chose qui dérive de B -- et je crois qu'il y a des restrictions dans le cas des dérivations virtuelles).
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Loïc Joly wrote:
Soit le cas suivant :
struct A
{
virtual void f();
};
struct B : A
{
virtual void f();
}
typedef void (A::*FctPtr)();
FctPtr fct = &A::f;
int main()
{
A *b = new B;
b->*fct();
Il y manque des parenthèses : ce que tu a écris est
l'équivalent de « b->*(fct()) », c-à-d qu'il appellerait une
fonction libre fct, qui doit renvoyer un pointeur à membre, et
puis accéderait au membre désigné (pour ne rien faire avec lui)
de l'objet désigné par b.
Essaie « (b->*fct)() ».
}
(désolé s'il y a des fautes de frappes, j'ai pas compilé le
code, c'est l'idée qui compte)
Dans ce cas, quelle fonction est appelée : A::f ou B::f ?
B::f ?
J'ai cherché dans la norme sans rien trouver de bien convainquant.
Le 10.3.12
Explicit qualification with the scope operator (5.1) suppresses the
virtual call mechanism.
§10.3/13 (au moins dans la version de travail le plus récente)
ne parle que vaguement des appels directs. Où il faut chercher,
c'est dans la section 5, sur la signification des expressions.
Surtout §5.2.2/1 (vers la fin) : « The function called in a
member function call is normally selected according to the
static type of the object expression (clause 10), but if that
function is virtual and is not specified using a qualified id
then the function actually called will be the final overrider
(10.3) of the selected function in the dynamic type of the
object expression ». Or, ici, la fonction est spécifiée au
moyen d'un pointeur à membre, qui n'est pas une « qualified
id ». Donc, si la fonction est virtuelle, la fonction réelement
appelée serait la supplantation finale de la fonction choisie
dans le type dynamique de l'expression designant l'objet.
Si tu as l'occasion de régarder dans l'ARM, Stroustrup y propose
une implémentation possible, qui correspond d'assez près à celle
utiliser dans CFront (et encore dans VC++, je crois) : un
pointeur à une function membre est en fait une structure, qui
contient l'information si la fonction est virtuelle ou non, et
le cas échéant, soi son adresse réele, soi l'indice de son
entrée dans le vtable. (L'autre implémentation que je connais,
c'est de générer un trampoline, c-à-d une fonction sans nom qui
ressemble à une fonction membre non-virtuelle de A, et qui
appelle la fonction en question, et de mettre l'adresse du
trampoline dans le pointeur. C'est celui qui sert aujourd'hui
dans g++ et dans Sun CC.)
Me fait penser que comme on a explicité A::f, il n'y aura pas
appel virtuel, mais j'avoue ne pas savoir si ce passage est
suffisant ou même approprié.
La suppression de la virtualité dépend de la syntaxe de l'appel.
Si la fonction est désignée par une expression qualifiée,
l'appel n'est jamais virtuelle. Sinon, l'appel est virtuel si la
fonction appelée est déclarée virtuelle.
En passant, c'est intéressant à noter qu'avec des pointeurs au
membre, on a même une forme assez restreinte de la virtualité
pour les données :
struct A {} ;
struct B : A { int i ; } ;
int A::*pi = static_cast< int A::* >( &B::i ) ;
void
f( A* p )
{
std::cout << p->*pi ;
}
C'est légal, et ça marche, dans la mesure où l'objet désigné par
p a réelement un type dynamique B (ou quelque chose qui dérive
de B -- et je crois qu'il y a des restrictions dans le cas des
dérivations virtuelles).
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Il y manque des parenthèses : ce que tu a écris est l'équivalent de « b->*(fct()) », c-à-d qu'il appellerait une fonction libre fct, qui doit renvoyer un pointeur à membre, et puis accéderait au membre désigné (pour ne rien faire avec lui) de l'objet désigné par b.
Essaie « (b->*fct)() ».
}
(désolé s'il y a des fautes de frappes, j'ai pas compilé le code, c'est l'idée qui compte)
Dans ce cas, quelle fonction est appelée : A::f ou B::f ?
B::f ?
J'ai cherché dans la norme sans rien trouver de bien convainquant. Le 10.3.12 Explicit qualification with the scope operator (5.1) suppresses the virtual call mechanism.
§10.3/13 (au moins dans la version de travail le plus récente) ne parle que vaguement des appels directs. Où il faut chercher, c'est dans la section 5, sur la signification des expressions. Surtout §5.2.2/1 (vers la fin) : « The function called in a member function call is normally selected according to the static type of the object expression (clause 10), but if that function is virtual and is not specified using a qualified id then the function actually called will be the final overrider (10.3) of the selected function in the dynamic type of the object expression ». Or, ici, la fonction est spécifiée au moyen d'un pointeur à membre, qui n'est pas une « qualified id ». Donc, si la fonction est virtuelle, la fonction réelement appelée serait la supplantation finale de la fonction choisie dans le type dynamique de l'expression designant l'objet.
Si tu as l'occasion de régarder dans l'ARM, Stroustrup y propose une implémentation possible, qui correspond d'assez près à celle utiliser dans CFront (et encore dans VC++, je crois) : un pointeur à une function membre est en fait une structure, qui contient l'information si la fonction est virtuelle ou non, et le cas échéant, soi son adresse réele, soi l'indice de son entrée dans le vtable. (L'autre implémentation que je connais, c'est de générer un trampoline, c-à-d une fonction sans nom qui ressemble à une fonction membre non-virtuelle de A, et qui appelle la fonction en question, et de mettre l'adresse du trampoline dans le pointeur. C'est celui qui sert aujourd'hui dans g++ et dans Sun CC.)
Me fait penser que comme on a explicité A::f, il n'y aura pas appel virtuel, mais j'avoue ne pas savoir si ce passage est suffisant ou même approprié.
La suppression de la virtualité dépend de la syntaxe de l'appel. Si la fonction est désignée par une expression qualifiée, l'appel n'est jamais virtuelle. Sinon, l'appel est virtuel si la fonction appelée est déclarée virtuelle.
En passant, c'est intéressant à noter qu'avec des pointeurs au membre, on a même une forme assez restreinte de la virtualité pour les données :
struct A {} ; struct B : A { int i ; } ;
int A::*pi = static_cast< int A::* >( &B::i ) ;
void f( A* p ) { std::cout << p->*pi ; }
C'est légal, et ça marche, dans la mesure où l'objet désigné par p a réelement un type dynamique B (ou quelque chose qui dérive de B -- et je crois qu'il y a des restrictions dans le cas des dérivations virtuelles).
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Loïc Joly
Merci à tous de vos réponses.
Il y manque des parenthèses : ce que tu a écris est l'équivalent de « b->*(fct()) », c-à-d qu'il appellerait une fonction libre fct, qui doit renvoyer un pointeur à membre, et puis accéderait au membre désigné (pour ne rien faire avec lui) de l'objet désigné par b.
Essaie « (b->*fct)() ».
Effectivement. C'est typiquement le genre du code où j'ai tendance à beaucoup compter sur le compilateur pour corriger mes lacunes syntaxiques.
J'ai cherché dans la norme sans rien trouver de bien convainquant. Le 10.3.12 Explicit qualification with the scope operator (5.1) suppresses the virtual call mechanism.
§10.3/13 (au moins dans la version de travail le plus récente) ne parle que vaguement des appels directs. Où il faut chercher, c'est dans la section 5, sur la signification des expressions. Surtout §5.2.2/1 (vers la fin) : « The function called in a member function call is normally selected according to the static type of the object expression (clause 10), but if that function is virtual and is not specified using a qualified id then the function actually called will be the final overrider (10.3) of the selected function in the dynamic type of the object expression ». Or, ici, la fonction est spécifiée au moyen d'un pointeur à membre, qui n'est pas une « qualified id ».
D'accord. Ce qui m'a induit en erreur, c'est que ce pointeur avait lui été crée à partir d'un « qualified id», mais visiblement, c'est uniquement au moment même de l'appel si ce dernier est utilisé que la résolution n'est pas virtuelle.
Si tu as l'occasion de régarder dans l'ARM, Stroustrup y propose une implémentation possible, qui correspond d'assez près à celle utiliser dans CFront (et encore dans VC++, je crois) : un pointeur à une function membre est en fait une structure, qui contient l'information si la fonction est virtuelle ou non, et le cas échéant, soi son adresse réele, soi l'indice de son entrée dans le vtable. (L'autre implémentation que je connais, c'est de générer un trampoline, c-à-d une fonction sans nom qui ressemble à une fonction membre non-virtuelle de A, et qui appelle la fonction en question, et de mettre l'adresse du trampoline dans le pointeur. C'est celui qui sert aujourd'hui dans g++ et dans Sun CC.)
C'est en fait vers une version manuelle de ce deuxième idiome que je me serais dirigé si la réponse avait été l'inverse de ce qu'elle est.
En passant, c'est intéressant à noter qu'avec des pointeurs au membre, on a même une forme assez restreinte de la virtualité pour les données :
struct A {} ; struct B : A { int i ; } ;
int A::*pi = static_cast< int A::* >( &B::i ) ;
void f( A* p ) { std::cout << p->*pi ; }
C'est légal, et ça marche, dans la mesure où l'objet désigné par p a réelement un type dynamique B (ou quelque chose qui dérive de B -- et je crois qu'il y a des restrictions dans le cas des dérivations virtuelles).
As-tu déjà rencontré des cas concrets où ce genre de chose était utilisé ? -- Loïc
Merci à tous de vos réponses.
Il y manque des parenthèses : ce que tu a écris est
l'équivalent de « b->*(fct()) », c-à-d qu'il appellerait une
fonction libre fct, qui doit renvoyer un pointeur à membre, et
puis accéderait au membre désigné (pour ne rien faire avec lui)
de l'objet désigné par b.
Essaie « (b->*fct)() ».
Effectivement. C'est typiquement le genre du code où j'ai tendance à
beaucoup compter sur le compilateur pour corriger mes lacunes syntaxiques.
J'ai cherché dans la norme sans rien trouver de bien convainquant.
Le 10.3.12
Explicit qualification with the scope operator (5.1) suppresses the
virtual call mechanism.
§10.3/13 (au moins dans la version de travail le plus récente)
ne parle que vaguement des appels directs. Où il faut chercher,
c'est dans la section 5, sur la signification des expressions.
Surtout §5.2.2/1 (vers la fin) : « The function called in a
member function call is normally selected according to the
static type of the object expression (clause 10), but if that
function is virtual and is not specified using a qualified id
then the function actually called will be the final overrider
(10.3) of the selected function in the dynamic type of the
object expression ». Or, ici, la fonction est spécifiée au
moyen d'un pointeur à membre, qui n'est pas une « qualified
id ».
D'accord. Ce qui m'a induit en erreur, c'est que ce pointeur avait lui
été crée à partir d'un « qualified id», mais visiblement, c'est
uniquement au moment même de l'appel si ce dernier est utilisé que la
résolution n'est pas virtuelle.
Si tu as l'occasion de régarder dans l'ARM, Stroustrup y propose
une implémentation possible, qui correspond d'assez près à celle
utiliser dans CFront (et encore dans VC++, je crois) : un
pointeur à une function membre est en fait une structure, qui
contient l'information si la fonction est virtuelle ou non, et
le cas échéant, soi son adresse réele, soi l'indice de son
entrée dans le vtable. (L'autre implémentation que je connais,
c'est de générer un trampoline, c-à-d une fonction sans nom qui
ressemble à une fonction membre non-virtuelle de A, et qui
appelle la fonction en question, et de mettre l'adresse du
trampoline dans le pointeur. C'est celui qui sert aujourd'hui
dans g++ et dans Sun CC.)
C'est en fait vers une version manuelle de ce deuxième idiome que je me
serais dirigé si la réponse avait été l'inverse de ce qu'elle est.
En passant, c'est intéressant à noter qu'avec des pointeurs au
membre, on a même une forme assez restreinte de la virtualité
pour les données :
struct A {} ;
struct B : A { int i ; } ;
int A::*pi = static_cast< int A::* >( &B::i ) ;
void
f( A* p )
{
std::cout << p->*pi ;
}
C'est légal, et ça marche, dans la mesure où l'objet désigné par
p a réelement un type dynamique B (ou quelque chose qui dérive
de B -- et je crois qu'il y a des restrictions dans le cas des
dérivations virtuelles).
As-tu déjà rencontré des cas concrets où ce genre de chose était utilisé ?
--
Loïc
Il y manque des parenthèses : ce que tu a écris est l'équivalent de « b->*(fct()) », c-à-d qu'il appellerait une fonction libre fct, qui doit renvoyer un pointeur à membre, et puis accéderait au membre désigné (pour ne rien faire avec lui) de l'objet désigné par b.
Essaie « (b->*fct)() ».
Effectivement. C'est typiquement le genre du code où j'ai tendance à beaucoup compter sur le compilateur pour corriger mes lacunes syntaxiques.
J'ai cherché dans la norme sans rien trouver de bien convainquant. Le 10.3.12 Explicit qualification with the scope operator (5.1) suppresses the virtual call mechanism.
§10.3/13 (au moins dans la version de travail le plus récente) ne parle que vaguement des appels directs. Où il faut chercher, c'est dans la section 5, sur la signification des expressions. Surtout §5.2.2/1 (vers la fin) : « The function called in a member function call is normally selected according to the static type of the object expression (clause 10), but if that function is virtual and is not specified using a qualified id then the function actually called will be the final overrider (10.3) of the selected function in the dynamic type of the object expression ». Or, ici, la fonction est spécifiée au moyen d'un pointeur à membre, qui n'est pas une « qualified id ».
D'accord. Ce qui m'a induit en erreur, c'est que ce pointeur avait lui été crée à partir d'un « qualified id», mais visiblement, c'est uniquement au moment même de l'appel si ce dernier est utilisé que la résolution n'est pas virtuelle.
Si tu as l'occasion de régarder dans l'ARM, Stroustrup y propose une implémentation possible, qui correspond d'assez près à celle utiliser dans CFront (et encore dans VC++, je crois) : un pointeur à une function membre est en fait une structure, qui contient l'information si la fonction est virtuelle ou non, et le cas échéant, soi son adresse réele, soi l'indice de son entrée dans le vtable. (L'autre implémentation que je connais, c'est de générer un trampoline, c-à-d une fonction sans nom qui ressemble à une fonction membre non-virtuelle de A, et qui appelle la fonction en question, et de mettre l'adresse du trampoline dans le pointeur. C'est celui qui sert aujourd'hui dans g++ et dans Sun CC.)
C'est en fait vers une version manuelle de ce deuxième idiome que je me serais dirigé si la réponse avait été l'inverse de ce qu'elle est.
En passant, c'est intéressant à noter qu'avec des pointeurs au membre, on a même une forme assez restreinte de la virtualité pour les données :
struct A {} ; struct B : A { int i ; } ;
int A::*pi = static_cast< int A::* >( &B::i ) ;
void f( A* p ) { std::cout << p->*pi ; }
C'est légal, et ça marche, dans la mesure où l'objet désigné par p a réelement un type dynamique B (ou quelque chose qui dérive de B -- et je crois qu'il y a des restrictions dans le cas des dérivations virtuelles).
As-tu déjà rencontré des cas concrets où ce genre de chose était utilisé ? -- Loïc
James Kanze
Loïc Joly wrote:
En passant, c'est intéressant à noter qu'avec des pointeurs au membre, on a même une forme assez restreinte de la virtualité pour les données :
struct A {} ; struct B : A { int i ; } ;
int A::*pi = static_cast< int A::* >( &B::i ) ;
void f( A* p ) { std::cout << p->*pi ; }
C'est légal, et ça marche, dans la mesure où l'objet désigné par p a réelement un type dynamique B (ou quelque chose qui dérive de B -- et je crois qu'il y a des restrictions dans le cas des dérivations virtuelles).
As-tu déjà rencontré des cas concrets où ce genre de chose étai t utilisé ?
Oui:-(. En fait, si je le connais, c'est parce que j'ai rencontré du code qui s'en servait. J'avais cru que c'était illégal, j'ai cherché dans la norme pour trouver le passage exact qui l'interdisait, et j'ai trouvé qu'au contraire, c'est explicitement permis et supporté.
N'empèche que je ne m'en servirai pas.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Loïc Joly wrote:
En passant, c'est intéressant à noter qu'avec des pointeurs au
membre, on a même une forme assez restreinte de la virtualité
pour les données :
struct A {} ;
struct B : A { int i ; } ;
int A::*pi = static_cast< int A::* >( &B::i ) ;
void
f( A* p )
{
std::cout << p->*pi ;
}
C'est légal, et ça marche, dans la mesure où l'objet désigné par
p a réelement un type dynamique B (ou quelque chose qui dérive
de B -- et je crois qu'il y a des restrictions dans le cas des
dérivations virtuelles).
As-tu déjà rencontré des cas concrets où ce genre de chose étai t utilisé ?
Oui:-(. En fait, si je le connais, c'est parce que j'ai
rencontré du code qui s'en servait. J'avais cru que c'était
illégal, j'ai cherché dans la norme pour trouver le passage
exact qui l'interdisait, et j'ai trouvé qu'au contraire, c'est
explicitement permis et supporté.
N'empèche que je ne m'en servirai pas.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
En passant, c'est intéressant à noter qu'avec des pointeurs au membre, on a même une forme assez restreinte de la virtualité pour les données :
struct A {} ; struct B : A { int i ; } ;
int A::*pi = static_cast< int A::* >( &B::i ) ;
void f( A* p ) { std::cout << p->*pi ; }
C'est légal, et ça marche, dans la mesure où l'objet désigné par p a réelement un type dynamique B (ou quelque chose qui dérive de B -- et je crois qu'il y a des restrictions dans le cas des dérivations virtuelles).
As-tu déjà rencontré des cas concrets où ce genre de chose étai t utilisé ?
Oui:-(. En fait, si je le connais, c'est parce que j'ai rencontré du code qui s'en servait. J'avais cru que c'était illégal, j'ai cherché dans la norme pour trouver le passage exact qui l'interdisait, et j'ai trouvé qu'au contraire, c'est explicitement permis et supporté.
N'empèche que je ne m'en servirai pas.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34