Question

J'ai une fonction du même nom, mais avec une signature différente dans une base et des classes dérivées. Lorsque j'essaie d'utiliser la fonction de la classe de base dans une autre classe qui hérite de la fonction dérivée, je reçois une erreur. Voir le code suivant:

class A
{
    public:
    void foo(string s){};
};

class B : public A
{
    public:
    int foo(int i){};
};

class C : public B
{
    public:
    void bar()
    {
        string s;
        foo(s);
    }
};

Je reçois le message d'erreur suivant du compilateur gcc:

In member function `void C::bar()': no matching function for call to `C::foo(std::string&)' candidates are: int B::foo(int)

Si je supprime int foo (int i) {}; de la classe B , ou si je le renomme de foo1 , tout fonctionne bien.

Quel est le problème avec cela?

Était-ce utile?

La solution

Les fonctions des classes dérivées qui ne remplacent pas les fonctions des classes de base mais qui portent le même nom masqueront les autres fonctions du même nom dans la classe de base.

Il est généralement considéré comme une mauvaise pratique d’avoir des fonctions dans les classes dérivées qui portent le même nom que celles de la classe bass qui ne sont pas destinées à remplacer les fonctions de la classe de base, car ce que vous voyez n’est généralement pas souhaitable. Il est généralement préférable d'attribuer des noms différents à différentes fonctions.

Si vous devez appeler la fonction de base, vous devez définir l'étendue de l'appel à l'aide de A :: foo (s) . Notez que cela désactiverait également tout mécanisme de fonction virtuelle pour A :: foo (string) en même temps.

Autres conseils

C’est parce que la recherche de nom s’arrête si elle trouve un nom dans l’une de vos bases. Il ne regardera pas plus loin dans d'autres bases. La fonction dans B ombres la fonction dans A. Vous devez déclarer à nouveau la fonction de A dans l'étendue de B, afin que les deux fonctions soient visibles depuis B et C:

class A
{
    public:
    void foo(string s){};
};

class B : public A
{
    public:
    int foo(int i){};
    using A::foo;
};

class C : public B
{
    public:
    void bar()
    {
        string s;
        foo(s);
    }
};

Modifier: la description réelle donnée par la norme est (à partir de 10.2 / 2):

  

Les étapes suivantes définissent le résultat de la recherche de nom dans une portée de classe, C. Tout d'abord, chaque déclaration du   nom dans la classe et dans chacun de ses sous-objets de classe de base est pris en compte. Un nom de membre f dans une sous-   L'objet B masque un nom de membre f dans un sous-objet A si A est un sous-objet de classe de base de B. Toutes les déclarations   qui sont si cachés sont éliminés de la considération Chacune de ces déclarations introduites par un   using-declaration est considéré comme appartenant à chaque sous-objet de C qui est du type contenant la déclaration.   nommée par la déclaration-using.96) Si le jeu de déclarations résultant ne provient pas entièrement de sous-objets   du même type ou si l'ensemble a un membre non statique et comprend des membres de sous-objets distincts, il y a   une ambiguïté et le programme est mal formé. Sinon, cet ensemble est le résultat de la recherche.

Voici ce que vous pouvez dire à un autre endroit (juste au-dessus):

  

Pour une expression id [ quelque chose comme "foo" ], la recherche de nom commence dans le champ de classe de cette opération; pour un identifiant qualifié [ quelque chose comme "A :: foo", A est un spécificateur de nom imbriqué ], la recherche de nom commence dans la portée du spécificateur de nom imbriqué. La recherche de nom a lieu avant le contrôle d'accès (3.4, clause 11).

([...] mis par moi). Notez que cela signifie que même si votre toto dans B est privé, ce dernier ne sera toujours pas trouvé (car le contrôle d’accès se produit plus tard).

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