2009-09-12 13 views
11

Estoy confundido: pensé que los datos protegidos eran de lectura/escritura por los niños de una clase determinada en C++.¿Los datos protegidos en la clase principal no están disponibles en la clase secundaria?

El fragmento a continuación falla al compilar en la EM Compilador

class A 
{ 
protected: 
    int data; 
}; 

class B : public A 
{ 
    public: 

    B(A &a) 
    { 
    data = a.data; 
    } 
}; 

int main() 
{ 
    A a; 
    B b = a; 
    return 0; 
} 

mensaje de error:

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86 
Copyright (C) Microsoft Corporation. All rights reserved. 

demoFail.cpp 
demoFail.cpp(12) : error C2248: 'A::data' : cannot access protected member declared in class 'A' 
     demoFail.cpp(4) : see declaration of 'A::data' 
     demoFail.cpp(2) : see declaration of 'A' 

¿Qué estoy haciendo mal?

Respuesta

10

Según TC++ PL, pág 404:

Una clase derivada puede acceder a una clase base protegida miembros sólo para los objetos de su propio tipo ... Esto evita errores sutiles que de otro modo ocurrirían cuando una clase derivada corrompe datos que pertenecen a otras clases derivadas.

Por supuesto, aquí es una manera fácil de solucionar este problema para su caso:

class A 
{ 
protected: 
    int data; 
}; 

class B : public A 
{ 
public: 
    B(const A &a) 
     : A(a) 
    { 
    } 
}; 

int main() 
{ 
    A a; 
    B b = a; 
    return 0; 
} 
+0

Umph. Para ser precisos, este caso es un caso ficticio solo para demostrar el problema. De hecho, quería hacer una lectura bastante exhaustiva de los datos que se pasan. –

+0

En cualquier caso, puede ensuciar solo con los datos protegidos en la parte A de este u otro objeto B. Si tiene una instancia A o una instancia C que también deriva de A, B no tiene derechos especiales sobre esos As. Si no puede seguir este consejo (haga de esto una parte de esta B copiándola para que sea la parte básica de esta B, a la que tiene acceso), entonces podría tener un problema de diseño que podría requerir una imagen más grande para responder. – UncleBens

+0

@rlbond: la codificación después de la hora de acosar ataca nuevamente. Esto solucionó mi problema. Gracias. :) –

0

El constructor de B es privado. Si no especificas nada, en una clase, el modificador predeterminado es privado (para las estructuras es público). Entonces en este ejemplo el problema es que no puede construir B. Cuando agrega public al constructor B surge un problema anoter:

B tiene el derecho de modificar la parte de A deriva de pero no otro A como en este caso.

Se podría hacer lo siguiente:

class A 
{ 
public: 
    A() 
     : data(0) 
    { 
    } 
    A(A &a) 
    { 
    data = a.data; 
    } 
protected: 
    int data; 
}; 

class B : public A 
{ 
public: 
    B(A &a) 
     : A(a) 
    { 
    } 
}; 

int main() 
{ 
    A a; 
    B b = a; 
    return 0; 
} 
+0

Eso es lo que pensaba, pero no es el problema. – rlbond

+0

@jde: eso es un error tipográfico, en realidad. Hacer que el constructor de B sea público produce el mismo error. –

+0

@Paul, corrija cualquier error tipográfico accidental en las preguntas, por lo que las respuestas posteriores no proponen la misma solución :) –

2

El estándar de C++ dice acerca de los miembros no estáticos protegidas a 11.5/1

Cuando un amigo o una La función de miembro de una clase derivada hace referencia a una función protegida de miembro no estático o miembro de datos no estáticos protegidos de una clase base, se aplica una verificación de acceso además de las descritas anteriormente en la cláusula 11. Excepto cuando se forma un puntero al miembro (5.3.1), th El acceso debe ser a través de un puntero, referencia u objeto de la propia clase derivada (o cualquier clase derivada de esa clase) (5.2.5). Si el acceso es para formar un puntero al miembro, el especificador de nombre anidado nombrará la clase derivada (o cualquier clase derivada de esa clase).

Además de solucionar las cosas mencionadas anteriormente por otros (constructor de B es privado), creo que el camino de rlbond lo hará bien. Sin embargo, una consecuencia directa del párrafo anterior de la norma es que la siguiente es posible utilizando un puntero miembro, lo que podría decirse que es un agujero en el sistema de tipos, por supuesto

class B : public A { 
public: 
    B(A &a){ 
    int A::*dataptr = &B::data; 
    data = a.*dataptr; 
    } 
}; 

Por supuesto, no se recomienda este código hacer, pero muestra que puede acceder a ella, si realmente necesita (que he visto de esta manera se utiliza para imprimir una std::stack, std::queue, std::priority_queue accediendo a su miembro contenedor protegido c)

+0

hi Johannes Schaub - litb ¿Me podría mostrar cómo acceder miembro protegido C en std :: pila o std :: cola tengo problema para acceder a él me dio un error C2248: 'std :: stack <_Ty> :: c': no ​​se puede acceder al miembro protegido declarado en la clase 'std :: stack <_Ty>' gracias –

1

Sólo no debería copiar un A objeto en un constructor B.La intención es dejar la inicialización de los miembros A 's de su propio constructor:

struct A { 
    A(const A& a): data(a.data) {} 
    protected: int data; 
}; 

struct B : public A { 
    B(const A& a): A(a) {} 
}; 
Cuestiones relacionadas