Est-ce une déclaration à l'aide censée cacher une fonction virtuelle héritée?
-
10-10-2019 - |
Question
struct level0
{
virtual void foo() = 0;
};
struct level1 : level0
{
virtual void foo() { cout <<" level1 " << endl; }
};
struct level2 : level1
{
virtual void foo() { cout <<" level2 " << endl; }
};
struct level3 : level2
{
using level1::foo;
};
int main()
{
level1* l1 = new level3;
l1->foo();
level3 l3;
l3.foo();
return 0;
}
le code ci-dessus en utilisant gcc donne
level2
level1
mais donne icc
level2
level2
Laquelle est correcte ou est-il pas défini par la norme?
Edit: Cela prouve qu'il ya un bug sûr, considérer la fonction principale suivante
int main()
{
level3 l3;
l3.foo(); // This prints level1
level3* pl3 = &l3;
pl3->foo(); // This prints level2
level3& rl3 = l3;
rl3.foo(); // This prints level1
level3& rpl3 = *pl3;
rpl3.foo(); // This prints level2
return 0;
}
Ainsi, le même objet lorsqu'il est utilisé directement produit des résultats différents et lorsqu'il est utilisé par un pointeur de même type produit des résultats différents !!!
La solution
Un exemple dans la section standard 10.3p2 montre clairement que l'utilisation de déclarations font pas surchargent des fonctions virtuelles.
Ceci est un connu g ++ bogue .
Comme vous l'avez remarqué, lorsque vous appelez la fonction membre via une référence ou pointeur, plutôt que d'un cas où le type de dynamique est connu, le bug ne se produit pas.
Autres conseils
using level1::foo;
introduit une fonction de foo
en classe level3
qui se réfère à level1::foo
.
Dans une déclaration à l'aide utilisée en tant que membre-déclaration, la spéci fi nom emboîtés er nomme une classe de base de la classe étant défini. Une telle déclaration introduit à l'aide-l'ensemble des déclarations trouvées par nom de membre recherche.
Cependant, comme level1::foo
est virtuel, je suppose que, en l'appelant, vous devez appeler level2::foo
, ainsi icc doit être droit.
Je ne suis pas si sûr, en tout cas.
La façon d'obtenir niveau1 niveau1 serait bien sûr:
struct level3 : level2
{
virtual void foo() { level1::foo(); }
};
Votre « en utilisant » la directive semble informer le compilateur que si vous avez un level3 et appel foo là-dessus, il devrait invoquer la version niveau1, mais il est n'écrasez pas cela à la vtable.
gcc semble erroné en raison de l'incompatibilité, pas sûr parce que je ne icc sais pas ce que la norme indique.