8

J'ai une classe qui ressemble à quelque chose comme ceci:Problème avec surcharge const/non-const résolution

class ClassA 
{ 
    public: 
    float Get(int num) const; 
    protected: 
    float& Get(int num); 
} 

En dehors de la classe, j'appelle la fonction Get().

float foo = classAInstance.Get(i); 

je me attends à ce appeler la version publique, mais des erreurs Visual Studio sur:

error C2248: 'ClassA::Get' : cannot access protected member declared in class 'ClassA' 

En commentant la surcharge protégée et en supprimant toutes les références à elle, le code compile.

Pourquoi le compilateur essaie-t-il d'utiliser le membre inaccessible quand un accessible est disponible? Existe-t-il un moyen accepté de forcer le compilateur à choisir la surcharge correcte? Y a-t-il une référence aux règles de résolution pour les fonctions des membres quelque part?

Répondre

7

Il est vrai que la résolution de surcharge a lieu avant les contrôles d'accessibilité. L'article 13.3 de la norme ([over.match]) dit:

résolution de surcharge est un mécanisme de sélection de la meilleure fonction d'appel donné une liste d'expressions qui sont être les arguments de l'appel et un ensemble de fonctions de candidats qui peut être appelé sur la base du contexte l'appel. Les critères de sélection pour la meilleure fonction sont le nombre d'arguments, comment les arguments correspondent à la liste de types de paramètres de la fonction candidate, comment (pour les fonctions membres non statiques) l'objet correspond au paramètre d'objet implicite, et certaines autres propriétés de la fonction candidate. [Note: La fonction sélectionnée par la résolution de surcharge n'est pas garantie pour être adaptée au contexte. Autres restrictions , tels que l'accessibilité de la fonction, peuvent rendre son utilisation dans le contexte d'appel mal formé. - note de fin]

La solution habituelle consiste à attribuer des noms différents aux fonctions publique et protégée.


Remarque, ce qui est utile parfois, par exemple:

class Blah 
{ 
    const std::string& name_ref; 

    Blah(const char*) = delete; 

public: 
    Blah(const std::string& name) : name_ref(name) {} 

    void do_something_with_name_ref() const; 
}; 

std::string s = "Blam"; 
Blah b(s); // ok 

Notez que name_ref ne sera lu à partir, il est donc approprié de le faire const. Cependant, les références const peuvent se lier à des temporaires et lier name_ref à une valeur temporaire serait une référence flottante, ce qui entraînerait un comportement indéfini dans do_something_with_name_ref().

Blah c("Kablooey!"); // would be undefined behavior 
        // the constructor overload makes this a compile error 

La surcharge du constructeur privé empêche une std::string temporaire d'être implicitement construit et lié.

+0

L'exemple semble dangereux. Étant donné 'string func();' et une expression de 'Blah b (func())' compilera et donnera toujours une référence qui pend. Ma règle ici est: * Ne jamais * conserver les paramètres 'const &'.Que dis-tu? –

+0

@MartinBa: Certainement vous voudriez aussi 'Blah (string &&) = delete;' –

+0

Hm. Et la question devient alors si la charge de 'const char 'est encore nécessaire du tout. le paramètre 'char *' se lierait-il à la version 'chaîne de caractères const &' ou à la version 'chaîne &&'? :-) –

5

La résolution de surcharge est effectuée en premier et la vérification d'accès plus tard.

Si vous avez à la fois une const et une surcharge non-const, ceci est résolu par la constité de l'objet pour lequel la fonction est appelée.

Questions connexes