2011-01-12 24 views
8

Este es un ejemplo de código que me molesta:¿Cómo acceder al método protegido en la clase base de la clase derivada?

class Base { 
    protected: 
    virtual void foo() = 0; 
}; 

class Derived : public Base { 
    private: 
    Base *b; /* Initialized by constructor, not shown here 
       Intended to store a pointer on an instance of any derived class of Base */ 

    protected: 
    virtual void foo() { /* Some implementation */ }; 
    virtual void foo2() { 
     this->b->foo(); /* Compilator sets an error: 'virtual void Base::foo() is protected' */ 
    } 
}; 

¿Cómo se accede a la función overrided protegida?

Gracias por su ayuda. : o)

+7

No creo que su implementación sea correcta. ¿Por qué tienes una instancia de Base como variable miembro? this-> b-> foo() intentaría llamar a un método virtual puro. – GWW

+1

Este programa no debe compilarse. No se puede crear una instancia de una clase abstracta ... a menos que 'b' apunte a una instancia de alguna otra clase derivada de' Base'. – 341008

+0

Omití precisión: el atributo Derived :: b está destinado a almacenar cualquier instancia de clases derivadas de Base –

Respuesta

8

Los miembros protegidos en una clase base solo son accesibles para el objeto actual.
Por lo tanto, puede llamar al this->foo(), pero no tiene permitido llamar al this->b->foo(). Esto es independiente de si Derived proporciona una implementación para foo o no.

La razón detrás de esta restricción es que, de otro modo, sería muy fácil eludir el acceso protegido. Usted acaba de crear una clase como Derived, y de repente también tiene acceso a partes de otras clases (como OtherDerived) que se suponía que eran inaccesibles para los de afuera.

+0

Gracias, ahora entiendo claramente las razones de la restricción ... Eso sería un agujero de seguridad ... ¡grande! –

+5

Por favor, no lo piense como un agujero de seguridad. Los modificadores de acceso no proporcionan ningún tipo de seguridad, solo podría leer la ubicación de la memoria si quisiera los datos. – DrYap

5

Normalmente, lo haría usando Base::foo(), que hace referencia a la clase base de la instancia actual.

Sin embargo, si su código necesita hacerlo de la forma en que lo intenta y no está permitido, entonces deberá hacer que foo() sea público o hacer de Derived un amigo de Base.

0

Llamar funciones base explícitamente con el operador de ámbito (Base :: foo()). Pero en este caso, la clase Base no define foo (es puramente virtual), por lo que no hay ninguna función que ejecutar cuando diga this->b->foo();, ya que b es un puntero a Base y no Derivado.

+1

Pero el código del OP no se refiere a la clase base de la instancia actual. Está accediendo a otra instancia, que presumiblemente es una clase derivada que implementa la función puramente virtual. (De lo contrario, no se pudo crear la instancia.) –

+0

@Jonathan Wood Entiendo lo que dices, pero yendo desde el código que ha publicado, parece que intenta crear una clase base abstracta (Base) y llama a un función virtual (Base :: foo()), que es un no-no (como GWW y 341008 también mencionados anteriormente). – Gemini14

0

¿Cómo se accede a la función protegida anulada?

--- desde donde?

Puede acceder a un miembro protegido solo a través de la herencia (aparte de los métodos de la misma clase). Digamos por ejemplo que tiene un class Derived1 que hereda de Derived, luego los objetos de Derived1 pueden llamar al foo().

EDIT: MSDN article en el especificador de acceso protegido.

1

Es un poco frágil, pero con las clases que definió aquí, ¿no funcionará?

virtual void foo2() { 
    reinterpret_cast<Derived *>(this->b)->foo(); 
} 

Los puntos reinterpret_cast en el VTABLE para el objeto de base, y pide que a través de esta miembros de acceso.

2

Una solución sería declarar una función protegida estática en Base que redirige la llamada a la función privada/protegida (foo en el ejemplo).

digamos que:

class Base { 
protected: 
    static void call_foo(Base* base) { base->foo(); } 
private: 
    virtual void foo() = 0; 
}; 

class Derived : public Base { 
private: 
    Base* b; 
protected: 
    virtual void foo(){/* Some implementation */}; 
    virtual void foo2() 
    { 
     // b->foo(); // doesn't work 
     call_foo(b); // works 
    } 
}; 

De esta manera, no se rompen encapsulación porque el diseñador de Base puede tomar una decisión explícita para permitir que todas las clases derivadas para llamar foo el uno del otro, evitando al mismo tiempo poner foo en la interfaz pública o convertir explícitamente todas las posibles subclases de Base en amigos.

Además, este método funciona independientemente de si foo es virtual o no, o si es privado o está protegido.

Here es un enlace a una versión en ejecución del código anterior y here otra versión de la misma idea con un poco más de lógica de negocios.

Cuestiones relacionadas