2011-01-28 12 views
17

No pude pensar en una mejor redacción para el título, por lo que es un poco engañoso, sin embargo, no estoy hablando de que un niño acceda a sus variables heredadas de su padre, lo cual es bastante fácil.Accediendo a las variables protegidas padre

Lo que estoy hablando es la siguiente:

class Parent { 
    protected: 
    Parent *target; 
    int hp; 
} 

class Child : public Parent { 
    public: 
    void my_func(); 
} 

void Child::my_func() { 
    target->hp -= 50; 
} 

Sin embargo, si intento compilar esto, se quejan de 'HP' ser "privada en este contexto". El problema es que el niño no intenta acceder a las variables de su propio padre, sino a alguna otra clase ', que puede o no ser un Niño.

Un objeto puede acceder a todas las variables y métodos (públicos, protegidos o privados) de otro objeto (dos instancias separadas en la memoria) que es de la misma clase, así que pensé que funcionaría con esto también, ya que hereda de la clase cuyas variables está intentando acceder, pero parece que estaba equivocado al asumirlo.

¿Algún consejo?

P.S. No es grosero ni nada, pero sé que puedo crear métodos get() y set(), pero esperaba una manera más limpia.

+0

Existen numerosos errores en el código tal como se escriben aquí (palabra clave 'class' incorrectamente en mayúsculas, sintaxis de herencia incorrecta, etc.) que estoy seguro son errores tipográficos que no están en el código original. Puede ser útil obtener un ejemplo mínimo que no se puede compilar, luego copiar y pegar el código exacto aquí. –

+1

@Tim Pensé que estarías conversando contigo mismo por un minuto allí, hasta que comparara los perfiles –

+0

Sí, debería hacer algo al respecto. No es tan único de un nombre como yo pensaba. :-) –

Respuesta

22

Las funciones miembro de una clase particular sólo tienen acceso a los miembros protegidos de clases base que realmente son subobjetos base de la Clase de objetos del mismo tipo de clase (o más tipos de derivados)

Los miembros de una clase no tienen acceso a miembros protegidos de otras instancias de esa clase base y también tienen prohibido acceder a miembros protegidos a través de una referencia o puntero al tipo de clase base incluso en tiempo de ejecución que ese puntero o referencia ser a un objeto que es del tipo de la clase cuya función miembro está intentando el acceso. El control de acceso se aplica en tiempo de compilación.

E.g.

class X 
{ 
protected: 
    int z; 
}; 

class Y : X 
{ 
public: 
    int f(const Y& y) 
    { 
     return y.z; // OK 
    } 

    int g(const X& x) 
    { 
     return x.z; // Error, Y::g has no access to X::z 
    } 
}; 

En su ejemplo, en la expresión target->hp, el acceso a target es legal porque tiene acceso a un miembro del objeto actual (que tiene el tipo de la clase de los que la función es miembro, Child) , pero el acceso al miembro hp no es legal porque el tipo de target no es un puntero a Child, sino un puntero a Parent.

+0

chapeau! ¡Gran ejemplo! –

+2

Quizás no lo dejé lo suficientemente claro en el PO, pero lo entiendo. Quiero saber si hay alguna forma de hacerlo sin los métodos get() y set(). – Infiltrator

+0

@Tim: Mi respuesta estaba tratando de ayudar a explicar su suposición incorrecta. Hay abusos pero debe arreglar la jerarquía de clases para que tenga el acceso que necesita. http://stackoverflow.com/questions/3364722/accessing-protected-member-of-template-parameter/3365221#3365221 –

-4

tratar de cambiar a este

Class Child : public Parent 
+1

El mismo problema ocurre con la herencia pública. –

+1

No tiene nada que ver con si 'Child' hereda pública o privadamente de' Parent'. Se trata de si un método 'Child' está intentando acceder a un miembro protegido de un' Parent' que es un subobjeto de clase base 'Child' o one eso no es. –

+3

-1 nada que ver con el problema –

0

hmm, por extraño que nadie lo mencionó hasta ahora, pero se puede declarar niño a ser un amigo del padre (tal vez porque su código no es muy clara acerca de qué es exactamente lo quiero hacer aquí)

class Parent { 
    friend class Child; 
    protected: 
    int hp; 
} 

class Child { 
    public: 
    void my_func(); 
    Parent *target; 
} 

esto permitiría el acceso. alternativamente, se podría escribir un método de acceso que es pública:

class Parent { 
public: 
    get_hp(){return hp;} 
protected: 
    int hp; 
} 
+0

Sí, podría hacerlo, y ese es mi truco por el momento, pero parece que rompe la "bajeza" de la herencia. No deberías necesitar hacer amigos con cada clase que herede de él para que funcione. – Infiltrator

+0

Además, como dije, soy consciente de que puedo usar los métodos set() y get(), que es lo que tu ejemplo es, esencialmente. Me gustaría ver si hay alguna manera de hacerlo de manera similar a como lo estoy intentando y usted podría hacerlo si no estuviera usando la herencia. – Infiltrator

+0

@Tim: Como dije en mi comentario a la respuesta de Charles, el problema es que desea romper la abstracción representada por la clase base. Necesitas preguntarte por qué quieres hacer eso. – sbi

4

Esto es tan fácil (es decir, el aparente malentendido del OP, es porque las personas no se toman el tiempo para leer el OP).

Simplemente haga que el niño sea amigo de la variable de los padres a la que necesita acceder.

O bien, puede hacer que el niño sea amigo de la clase para padres.

De esta forma, cualquier niño tiene acceso a las variables de miembro de cualquier padre, exactamente de la manera que usted espera.

class Child; 

class Parent { 
    protected: 
    Parent *target; 
    int hp; 
    friend void Child::my_func(); 
} 

class Child : public Parent { 
    public: 
    void my_func(); 
} 

void Child::my_func() { 
    target->hp -= 50; 
} 

El inconveniente de esto es que CADA niño puede tener acceso a las variables de TODOS los padres. Sin embargo, debe tener en cuenta que, en su caso, el compilador no puede saber que el objetivo Parent * es la misma instancia que el secundario. Dado que lo denominaste objetivo, esperaría que TODOS los niños tuvieran acceso a las variables de TODOS los padres es lo que deseas.

Aquí hay otra posibilidad. Haga que todos los demás usen una interfaz para acceder a los padres y que solo su hijo use la clase de padres actual. El resultado es el mismo sin embargo. Todos los niños tienen acceso a todas las variables de los padres.

Estás confundiendo clase con instancia. El niño tiene acceso a las mismas variables miembro de la clase base que es de la misma INSTANCIA.

+0

No se puede hacer que una clase sea amiga de una variable. ¿Quisiste decir "clase" en su lugar? – sbi

+0

También tenga en cuenta mis comentarios a Tim en la respuesta de Charles. Lo que dije sobre 'protected' es aún más cierto sobre' friend': rompe la abstracción de una clase, conectando estrechamente al amigo con la implementación de la clase. El acoplamiento cerrado siempre es malo. Use 'friend' tanto como sea necesario, pero lo menos posible. – sbi

+0

Copiar y pegar: Sí, podría hacer eso, y ese es mi truco por el momento, pero parece que rompe la "caída" de la herencia. No deberías necesitar hacer amigos con cada clase que herede de él para que funcione. – Infiltrator

Cuestiones relacionadas