Question

Je lisais la FAQ de C ++ 0x de Stroustrup et je me suis retrouvé coincé avec ce code. Considérez le code suivant

struct A
{
    void f(double)
    {
        std::cout << "in double" << std::endl;
    }
};

struct B : A
{
    void f(int)
    {
        std::cout << "in int" << std::endl;
    }
};


int main()
{
    A a; a.f(10.10);  // as expected, A.f will get called
    B b; b.f(10.10);  // This calls b.f and we lose the .10 here
    return 0;
}

Je pensais que lorsqu'un type est hérité, tous les membres protégés et publics seront accessibles à partir de la classe dérivée. Mais selon cet exemple, il semble que je me trompe. Je m'attendais à ce que b.f appelle les classes de base f . J'ai eu le résultat attendu en changeant la classe dérivée comme

struct B : A
{
    using A::f;
    void f(int)
    {
        std::cout << "in int" << std::endl;
    }
};

Questions

  1. Pourquoi cela ne fonctionnait-il pas dans le premier code?
  2. Quelle section de la norme C ++ décrit toutes ces règles de portée?
Était-ce utile?

La solution

Le premier code fonctionne comme c ++ est conçu pour fonctionner.

La résolution de surcharge suit un ensemble de règles très compliqué. La bible 15.2.2 de la version c ++ de Stroustrup "[A] mbiguities entre des fonctions de classes de base différentes ne sont pas résolues en fonction des types d'argument."

Il explique ensuite l'utilisation de "utilisation". comme vous l'avez décrit.

Il s'agissait d'une décision de conception dans le langage.

J'ai tendance à suivre le livre Stroustrup plutôt que le standard, mais je suis sûr qu'il est là.

[Modifier]

Le voici (de la norme):

Chapitre 13

Lorsque deux déclarations différentes ou plus sont spécifiées pour un seul nom dans la même portée, ce nom est dit surchargé.

Et ensuite:

13.2 Correspondance de déclaration

1 Deux déclarations de fonction du même nom font référence à la même fonction si elles ont la même portée et ont des déclarations de paramètres équivalentes (13.1). Un membre de fonction d’une classe dérivée n’est pas dans la même portée qu’un membre de fonction de le même nom dans une classe de base.

Autres conseils

C’est parce que A :: f est " caché " plutôt que " surchargé " ou "substitué". Référez-vous:

http://www.parashift.com /c++-faq-lite/strange-inheritance.html#faq-23.9

Recherchez la résolution de la surcharge . Une question similaire, mais pas identique .

En C ++, il n'y a pas de surcharge entre les étendues, les portées dans les classes dérivées ne font pas exception. (Selon le langage de programmation C ++)

Pour plus d'informations, consultez http: //www.research. att.com/~bs/bs_faq2.html#overloadderived

Dans le premier cas, la méthode de la classe de base 'f' est cachée par la méthode de la classe dérivée. En C ++, il n'y a pas de surcharge sur des portées; c'est pourquoi il ne s'appelle pas. La norme C ++ explique toutes les règles de recherche de nom de membre dans la section 10.2 Recherche de nom de membre [class.member.lookup] . HTH

La première version de code devrait vraiment appeler B :: f. Vous redéfinissez le symbole " f " in struct "B", le masque original "f" est donc masqué. de struct "A". Ce n'est pas une surcharge, comme cela peut paraître.

Chaque fois que le compilateur rencontre b.f (), il recherche le " B " struct pour un symbole "f". Il y est présent et le compilateur décide alors d'appeler B :: f (int), en convertissant double en int. Il ne voit pas la nécessité d'analyser la classe parente pour une fonction plus appropriée ...

Cependant, lorsque vous ajoutez "en utilisant A :: f", il s’agit d’une directive explicite permettant au compilateur d’analyser une classe parente à la recherche du symbole "f". Maintenant, la classe B a deux fonctions surchargées: pour int et pour double.

Je pense aussi que vous pourriez écrire b.A :: f () sans utiliser "utiliser". directive dans l'exemple d'origine ...

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