¿Los datos protegidos en la clase principal no están disponibles en la clase secundaria?

StackOverflow https://stackoverflow.com/questions/1414506

  •  06-07-2019
  •  | 
  •  

Pregunta

Estoy confundido: pensé que los datos protegidos eran leídos / escribibles por los hijos de una clase dada en C ++.

El siguiente fragmento no se compila en el compilador de MS

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?

¿Fue útil?

Solución

De acuerdo con TC ++ PL, pg 404:

  

Una clase derivada puede acceder a una clase base & # 8217; miembros protegidos solo para objetos de su propio tipo ... Esto evita errores sutiles que de otro modo ocurrirían cuando una clase derivada corrompe los datos que pertenecen a otras clases derivadas.

Por supuesto, aquí hay una manera fácil de arreglar esto 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;
}

Otros consejos

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

  

Cuando un amigo o una función miembro de una clase derivada hace referencia a una función miembro no estática protegida o miembro de datos no estático protegido 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 a miembro (5.3.1), el acceso debe ser a través de un puntero, referencia u objeto de la clase derivada (o cualquier clase derivada de esa clase) (5.2.5). Si el acceso es para formar un puntero a miembro, el especificador de nombre anidado nombrará la clase derivada (o cualquier clase derivada de esa clase).

Además de arreglar las cosas mencionadas anteriormente por otros (el constructor de B es privado), creo que la forma de rlbond lo hará bien. Sin embargo, una consecuencia directa del párrafo anterior de la Norma es que lo siguiente es posible usando un puntero de miembro, 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 hacer este código, pero muestra que puede acceder a él, si realmente lo necesita (he visto que de esta manera se utiliza para imprimir un std :: stack , std :: queue , std :: priority_queue accediendo a su miembro contenedor protegido c )

Simplemente no debería copiar un objeto A en un constructor B . La intención es dejar la inicialización de los miembros de A a 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 ) {}
};

El constructor de B es privado. Si no especifica nada, en una clase, el modificador predeterminado es privado (para 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 anotador:

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

Puede 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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top