2012-09-04 46 views
21

Tengo el siguiente código:No se puede acceder miembro protegido de la clase base en la clase derivada

struct A { 
protected: 
    A() {} 

    A* a; 
}; 

struct B : A { 
protected: 
    B() { b.a = &b; } 

    A b; 
}; 

extrañamente no se compilará. El culpable es la asignación b.a = &b;: tanto GCC como clang se quejan de que A() está protegido, lo que no debería ser un problema porque B hereda A. ¿En qué esquina oscura del estándar he entrado?

+3

Solo se puede acceder a los miembros 'protegidos' de' this' 'base (misma instancia). 'this' y' b' no son la misma instancia. – jrok

+2

@MikeSeymour nope. (pero admito que pensé exactamente lo mismo hasta hace poco) –

+0

Estoy seguro de que esto se ha preguntado muchas veces antes, pero es difícil encontrar el duplicado exacto. – dasblinkenlight

Respuesta

21

El significado de protected es que el tipo derivado tendrá acceso a ese miembro de su propia base de y no de cualquier objeto al azar *. En su caso, para el cuidado intentando modificar b 's miembro de que está fuera de su control (es decir, se puede establecer this->a, pero no b.a)

hay un truco para conseguir que esto funcione si está interesado, pero una una mejor solución sería refactorizar el código y no depender de los hacks. Podría, por ejemplo, proporcionar un constructor en A que toma un A* como argumento (este constructor debe ser pública) y luego inicializarlo en la lista de inicialización de B:

A::A(A* p) : a(p) {} 
B::B() : b(&b) {} 

*protected subvenciones accede al miembro base en cualquier instancia de su propio tipo o derivada de su propio tipo.

+1

+1: Siempre escucho el dicho "el control de acceso funciona por clase, no una base por objeto ", pero parece' protegido' es la única excepción a esta regla? –

+1

@JesseGood: No realmente, todavía es por clase. Tal vez fui demasiado vago en la respuesta. Usted tiene acceso al miembro en cualquier objeto de tipo 'B' o derivado de' B', simplemente no en objetos de tipo 'A' o derivados de 'A' (que no son' B') –

+0

Tenga en cuenta que también puede engañar el compilador usa un reinterpret_cast. Feo, y puede ser peligroso, pero ... – Macmade

0

Todos los compiladores que probé se quejaban de varias cosas, y específicamente el constructor protegido sería un problema incluso si se eliminaba la declaración de asignación.

No tiene acceso a los miembros protected de cualquier instancia de un tipo del que deriva. Este problema se aclara en los ejemplos de 11.4p1.

class B { 
protected: 
    int i; 
    static int j; 
}; 

class D1 : public B { 
}; 

class D2 : public B { 
    void mem(B*, D1*); 
}; 

void D2::mem(B* pb, D1* p1) { 
    pb->i = 1; // ill-formed 
    p1->i = 2; // ill-formed 
    // ... 
} 
2

En realidad, hay dos problemas separados aquí.

La primera es que la línea no solo hace una asignación, sino que intenta inicializar la clase base (que funciona bien) y el miembro b. Para crear el miembro b que necesita para construirlo, y como miembro necesita public acceso a un constructor, que no tiene.

A continuación, la asignación también es incapaz de acceder miembro no pública de b porque, de nuevo, no es de tipo B pero escribir los A lugar.

Recuerde que protected significa que puede acceder a partes de Aa través de un B objeto (o niño) solamente.

En este caso, cuéntenos su problema real y podemos intentar ayudar a resolverlo. Heredar y componer del mismo tipo es un olor de diseño.

+0

"Heredar y componer del mismo tipo es un olor de diseño". ¿Por qué es? ¿Puedes elaborar? Recientemente estoy teniendo un diseño y en la clase derivada, hay varias instancias de base (composición). En tal escenario, necesito acceder a miembros protegidos de esas instancias base desde dentro de mis funciones de clase derivadas: errores de compilación allí. Si el especificador de acceso protegido es por clase (en lugar de por instancia), esto debería permitirse, ¿por qué no? – h9uest

+0

Hola Mark. Preparé una pregunta específica a continuación, ¿podrías tomar un momento para iluminarme?(La norma no dice nada similar a "acceder a la base A TRAVÉS de un objeto derivado", la cláusula 11 en la página 237 establece claramente que un nombre protegido puede ser utilizado por clases derivadas de esa clase. En otras palabras, funciona en base a clase y instancia no entra en la imagen.) Saludos. http://stackoverflow.com/questions/34588930/c-protected-fail-to-access-bases-protected-member-from-within-derived-class/34589641?noredirect=1#comment56950922_34589641 – h9uest

0

Parece una gran limitación del lenguaje C++.¿Cómo resolvería este problema como:

class Node 
{ 
public: 
void Save(); 
protected: 
virtual void SaveState(int type) = 0; 
}; 

class BinaryNode : public Node 
{ 
protected: 
Node *left; 
Node *right; 

virtual void SaveState(int type) override 
{ 
    left->SaveState(type); 
    right->SaveState(type); 
} 
}; 

En este ejemplo no quiero hacer método SaveState visible fuera Node jerarquía. Solo el método Save debe ser public.

+0

Si se oculta un "nodo" detalles del proceso de guardado del usuario, entonces no debe influir en él en "BinaryNode", porque no conoce el tipo exacto de "Node *" y no puede adivinar su implementación interna. En otro caso, debe agregar algunos argumentos para "Guardar" para influir en él desde el exterior o hacer que su ejemplo sea más claro –

Cuestiones relacionadas