c++ - métodos - qué son los atributos de clase estáticos
¿Cómo llamar a un método estático desde una clase base privada? (5)
Debido al diseño de una biblioteca de terceros, tengo algo como el siguiente código:
struct Base
{
static void SomeStaticMethod(){}
};
struct Derived1: private Base {};
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
Base::SomeStaticMethod();
}
};
int main() {
Derived2 d2;
d2.SomeInstanceMethod();
return 0;
}
Recibo el error del compilador C2247 con MSVC:
Base :: SomeStaticMethod no accesible porque Derived1 usa private para heredar de Base.
Sé que no puedo acceder a los miembros de la Base
desde Derived2
través de la herencia debido al especificador privado, pero todavía debería poder llamar a un método estático de Base
, independientemente de cualquier relación de herencia entre la Base
y Derived2
.
¿Cómo resuelvo la ambigüedad y le digo al compilador que solo hago una llamada a un método estático?
Creo que la respuesta de michalsrb es mejor, pero para completar:
namespace
{
void SomeStaticMethodProxy()
{
return Base::SomeStaticMethod();
}
}
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
SomeStaticMethodProxy();
}
};
También funcionará.
Hacer esto:
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
::Base::SomeStaticMethod();
// ^^
// Notice leading :: for accessing root namespace.
}
};
Otras respuestas proporcionan una manera de resolver el problema, intentaré explicar qué está sucediendo. Es por el nombre de clase inyectado .
9.2 (N4594)
[...] El nombre de clase también se inserta en el alcance de la clase en sí; Esto se conoce como el nombre de clase inyectada. A los fines de la verificación de acceso, el nombre de clase inyectada se trata como si fuera un nombre de miembro público. [...]
Tenga en cuenta que incluso si escribe Base::SomeStaticMethod()
, obviamente se busca SomeStaticMethod
en el ámbito Base
(es el nombre calificado), pero el nombre Base
también debe buscarse de alguna manera , (en este ejemplo, como un nombre no calificado (porque no aparece después del operador de resolución de alcance))
Lo que sucede es que cuando busca el nombre (no calificado) Base
en Derived2
, primero se Derived2
alcance Derived2
, luego se Derived1
alcance Derived1
y luego se busca el alcance Base
y finalmente se encuentra el nombre de la clase inyectada . Luego se lleva a cabo el control de acceso (porque el control de acceso se realiza después de la búsqueda del nombre) y encontrará que el nombre que buscó es un miembro de Base
al que no se puede acceder desde Derived2
.
Puedes hacer esto si quieres llamarlo a través de la jerarquía:
struct Derived1: private Base {
protected:
using Base::SomeStaticMethod;
};
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
Derived1::SomeStaticMethod();
}
};
De lo contrario, haz lo que @michalsrb menciona si quieres llamarlo directamente en Base
.
Un par de posibilidades:
No use la estructura de herencia para llamar al método. Use
::Base::SomeStaticMethod()
para llamarlo.Base
es accesible en el espacio de nombres global.Coloque la función
private
en el espacio de nombres deDerived1
escribiendousing Base::SomeStaticMethod;