8

tengo una clase que se ve algo como esto:Problemas con const resolución/no constante sobrecarga

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

fuera de la clase, que llamo la función get().

float foo = classAInstance.Get(i); 

me esperaba esto para llamar la versión pública, pero los errores en lugar de Visual Studio salida:

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

Al comentar la sobrecarga protegida y la eliminación de todas las referencias a ella, el código se compila.

¿Por qué el compilador intenta usar el miembro inaccesible cuando uno accesible está disponible? ¿Hay una forma aceptada de forzar al compilador a elegir la sobrecarga correcta? ¿Hay alguna referencia a las reglas de resolución para las funciones miembro en alguna parte?

Respuesta

7

Es cierto, la resolución de sobrecarga se lleva a cabo antes de las comprobaciones de accesibilidad. Sección 13.3 de la norma ([over.match]) dice:

resolución de sobrecarga es un mecanismo para seleccionar la mejor función para llamar dado una lista de expresiones que son ser los argumentos de la llamada y un conjunto de funciones candidatas que se puede llamar en función del contexto de la llamada. Los criterios de selección para la mejor función son el número de argumentos, qué tan bien coinciden los argumentos con la lista de tipos de parámetros de la función candidata, qué tan bien (para las funciones miembro no estáticas) el objeto coincide con el parámetro de objeto implícito, y ciertas otras propiedades de la función candidata. [Nota: La función seleccionada por resolución de sobrecarga no garantiza que sea apropiada para el contexto. Otras restricciones , como la accesibilidad de la función, pueden hacer que su uso en el contexto de llamada esté mal formado. - nota final]

La solución habitual es dar diferentes nombres a las funciones pública y protegida.


Nota, esto es útil a veces, ejemplo:

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 

Tenga en cuenta que name_ref solamente se leerá desde, por lo que es adecuada para que sea const. Sin embargo, las referencias const pueden vincularse a temporales, y el enlace name_ref a un temporal sería una referencia pendiente, lo que da como resultado un comportamiento indefinido en do_something_with_name_ref().

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

La sobrecarga del constructor privado impide que un temporal std::string de ser construida de manera implícita y atado.

+0

El ejemplo parece peligroso. Dado 'string func();' y una expresión de 'Blah b (func())' se compilará y aún dará como resultado una referencia colgante. Mi regla aquí es: * Nunca * retener los parámetros 'const &'.¿Qué dices? –

+0

@MartinBa: Ciertamente también querría 'Blah (string &&) = delete;' –

+0

Hm. Y la pregunta entonces se convierte si la carga de 'const char' todavía se requiere en absoluto. ¿el parámetro 'char *' se uniría a la versión 'string const &' o a la versión 'string &&'? :-) –

5

La resolución de sobrecarga se realiza primero, y la comprobación de acceso más tarde.

Si tiene una const y una sobrecarga sin const, esto se resuelve por la constness del objeto que se llama la función.

Cuestiones relacionadas