usar son qué métodos metodos metodo los estáticos estaticos estatico entre diferencia definicion cuando clases clase atributos atributo c++ static-methods private-inheritance

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:

  1. 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.

  2. Coloque la función private en el espacio de nombres de Derived1 escribiendo using Base::SomeStaticMethod;