Miembros privados y protegidos: C ++

276

¿Puede alguien aclararme la diferencia entre privatey los protectedmiembros en las clases?

Yo entiendo de convenciones mejores prácticas que las variables y funciones que no son llamados fuera de la clase deben hacerse private- pero mirando a mi MFC proyecto, MFC parece estar a favor protected.

¿Cuál es la diferencia y cuál debo usar?

Konrad
fuente

Respuestas:

374

Los miembros privados solo son accesibles dentro de la clase que los define.

Los miembros protegidos son accesibles en la clase que los define y en las clases que heredan de esa clase.

Editar: Ambos también son accesibles por amigos de su clase, y en el caso de miembros protegidos, por amigos de sus clases derivadas.

Edición 2: use lo que tenga sentido en el contexto de su problema. Debe intentar hacer que los miembros sean privados siempre que pueda para reducir el acoplamiento y proteger la implementación de la clase base, pero si eso no es posible, use miembros protegidos. Consulte las preguntas frecuentes de C ++ para comprender mejor el problema. Esta pregunta sobre variables protegidas también podría ayudar.

Firas Assaad
fuente
12
El enlace a C ++ FAQ Lite se ha movido a isocpp.org/wiki/faq/basics-of-inheritance
avner
134

Los miembros públicos de una clase A son accesibles para todos y para todos.

Los miembros protegidos de una clase A no son accesibles fuera del código de A, pero son accesibles desde el código de cualquier clase derivada de A.

Los miembros privados de una clase A no son accesibles fuera del código de A, o del código de cualquier clase derivada de A.

Entonces, al final, elegir entre protegido o privado es responder las siguientes preguntas: ¿Cuánta confianza está dispuesto a depositar en el programador de la clase derivada?

De forma predeterminada , suponga que la clase derivada no es de confianza y haga que sus miembros sean privados . Si tiene una muy buena razón para dar acceso libre de los componentes internos de la clase madre a sus clases derivadas, puede protegerlos.

paercebal
fuente
La clase derivada debe ser un tipo de su clase, y los datos protegidos de la clase base son parte de los datos de la clase derivada. Se espera que el escritor de la clase derivada maneje estos datos correctamente o es un error. Sin embargo, los datos privados en una clase base son algo que el escritor de la clase derivada no controla.
CashCow
@CashCow the protected data of the base class is part of the data of the derived class.De hecho. ¿No es mejor, entonces, que el escritor de la clase derivada declare esos datos en su clase, en lugar de los míos? ... :-) ... The writer of the derived class is expected to handle this data properly or it is a bug.En el patrón NVI, el objetivo es hacer que todo sea privado, incluyendo métodos, para limitar el daño que el escritor de clase derivado podría hacer a la jerarquía. Los métodos protegidos ya son un problema potencial. No estoy convencido de que agravar esto usando el estado protegido sea el enfoque correcto.
paercebal
Podría ser, lo que requeriría tener "captadores" virtuales en la clase base para acceder a él. Y aunque puede tener clases intermedias para hacer las diferentes formas en que se puede implementar el patrón de datos, no siempre es práctico hacerlo. Por ejemplo, un "patrón", común en los lenguajes que no tienen un modificador "const", aunque no es necesario la mayor parte del tiempo en C ++, es tener una clase base de solo lectura y clases derivadas de escritura. En C ++ esto también puede ser bueno simplemente porque desea más de una forma posible de cargar (inicializar) los datos.
CashCow
Hay varias formas de hacer eso. Haz que tus clases de serialización sean amigos. Ponga todos sus datos en una estructura con acceso público, pero su clase tiene un miembro privado de esta variable ... Miembros protegidos y clases derivadas para cargarlos desde cualquier fuente que a veces es más fácil.
CashCow
63

Se puede acceder a los miembros protegidos desde clases derivadas. Los privados no pueden.

class Base {

private: 
  int MyPrivateInt;
protected: 
  int MyProtectedInt;
public:
  int MyPublicInt;
};

class Derived : Base
{
public:
  int foo1()  { return MyPrivateInt;} // Won't compile!
  int foo2()  { return MyProtectedInt;} // OK  
  int foo3()  { return MyPublicInt;} // OK
};‌‌

class Unrelated 
{
private:
  Base B;
public:
  int foo1()  { return B.MyPrivateInt;} // Won't compile!
  int foo2()  { return B.MyProtectedInt;} // Won't compile
  int foo3()  { return B.MyPublicInt;} // OK
};

En términos de "mejores prácticas", depende. Si incluso existe una leve posibilidad de que alguien desee obtener una nueva clase de la existente y necesite acceso a miembros internos, hágalos protegidos, no privados. Si son privados, tu clase puede ser difícil de heredar fácilmente.

Roddy
fuente
3
Le ruego que difiera: si existe una leve posibilidad de que ninguna subclase lo necesite, hágalo privado. A menos que tenga la intención de tener su clase subclase, utilice el patrón de método de plantilla.
xtofl
23

La razón por la que MFC favorece la protección es porque es un marco. Probablemente desee subclasificar las clases MFC y, en ese caso, se necesita una interfaz protegida para acceder a métodos que no son visibles para el uso general de la clase.

Toon Krijthe
fuente
9

Todo depende de lo que quieras hacer y de lo que quieras que las clases derivadas puedan ver.

class A
{
private:
    int _privInt = 0;
    int privFunc(){return 0;}
    virtual int privVirtFunc(){return 0;}
protected:
    int _protInt = 0;
    int protFunc(){return 0;}
public:
    int _publInt = 0;
    int publFunc()
    {
         return privVirtFunc();
    }
};

class B : public A
{
private:
    virtual int privVirtFunc(){return 1;}
public:
    void func()
    {
        _privInt = 1; // wont work
        _protInt = 1; // will work
        _publInt = 1; // will work
        privFunc(); // wont work
        privVirtFunc(); // wont work
        protFunc(); // will work
        publFunc(); // will return 1 since it's overridden in this class
    }
}
Mats Fredriksson
fuente
6

Los atributos y métodos marcados como protectedson, a diferencia de los privados, aún visibles en las subclases.

A menos que no desee usar o proporcionar la posibilidad de anular el método en posibles subclases, los haría private.

fhe
fuente
2
Una clase derivada puede anular las funciones virtuales privadas de su base
James Hopkin
6

Claro, eche un vistazo a la pregunta de Variables de miembros protegidos . Se recomienda utilizar privado como predeterminado (al igual que C ++ classses do) para reducir el acoplamiento. Las variables miembro protegidas son siempre una mala idea, las funciones miembro protegidas se pueden utilizar, por ejemplo, para el patrón Método de plantilla.

xtofl
fuente
Es curioso, lo edité en mi publicación antes de ver la tuya. Votado porque las aves de una pluma tropiezan con el mismo enlace :)
Firas Assaad
4

Solo los descendientes de la clase pueden acceder a los miembros protegidos y mediante el código del mismo módulo. Solo se puede acceder a los miembros privados por la clase en la que se declaran y por código en el mismo módulo.

Por supuesto, las funciones de amigo arrojan esto por la ventana, pero bueno.

Ignacio Vazquez-Abrams
fuente
4

los miembros privados solo son accesibles desde la clase, los miembros protegidos son accesibles en la clase y las clases derivadas. Es una característica de la herencia en los idiomas OO.

Puede tener herencia privada, protegida y pública en C ++, que determinará a qué clases derivadas puede acceder en la jerarquía de herencia. C #, por ejemplo, solo tiene herencia pública.

PhilGriffin
fuente
3

privado = accesible solo por la nave nodriza (clase base) (es decir, solo mis padres pueden ir a la habitación de mis padres)

protegido = accesible por nave nodriza (clase base) y sus hijas (es decir, solo mis padres pueden ir a la habitación de mis padres, pero dieron permiso a su hijo / hija para entrar a la habitación de los padres)

público = accesible por nave nodriza (clase base), hija y todos los demás (es decir, solo mis padres pueden ir a la habitación de mis padres, pero es una fiesta en casa - mi casa su casa)

Johan K. Rhodes
fuente
2

Dado que no se necesita ninguna función de miembro público para buscar y actualizar miembros protegidos en la clase derivada, esto aumenta la eficiencia del código y reduce la cantidad de código que necesitamos escribir. Sin embargo, se supone que el programador de la clase derivada debe estar al tanto de lo que está haciendo.

nulo
fuente
Siempre puede usar una función en línea implementada en la declaración de clase. El compilador optimizará eso (y esa sería una buena manera de imponer el acceso de solo lectura a una variable miembro privada, por ejemplo).
Paul Sanders
2

privatese prefiere para los datos del miembro. Los miembros en las clases de C ++ son privatepor defecto.

publices preferido para las funciones de los miembros, aunque es una cuestión de opinión. Al menos algunos métodos deben ser accesibles. publicEs accesible para todos. Es la opción más flexible y menos segura. Cualquiera puede usarlos y cualquiera puede abusar de ellos.

privateno es accesible en absoluto. Nadie puede usarlos fuera de la clase, y nadie puede usarlos mal. Ni siquiera en clases derivadas.

protectedes un compromiso porque puede usarse en clases derivadas. Cuando deriva de una clase, comprende bien la clase base y tiene cuidado de no hacer un mal uso de estos miembros.

MFC es un contenedor de C ++ para la API de Windows, prefiere publicy protected. Clases generadas por Visual Studio Asistente tienen una mezcla de fea protected, publicy privatemiembros. Pero hay algo de lógica en las clases de MFC.

Miembros como SetWindowTextson publicporque a menudo necesita acceder a estos miembros.

Los miembros como OnLButtonDown, manejan las notificaciones recibidas por la ventana. No deben ser accedidos, por lo tanto son protected. Todavía puede acceder a ellos en la clase derivada para anular estas funciones.

Algunos miembros tienen que hacer hilos y bucles de mensajes, no se debe acceder a ellos ni anularlos, por lo que se declaran como private

En estructuras C ++, los miembros son publicpor defecto. Las estructuras generalmente se usan solo para datos, no para métodos, por lo tanto, la publicdeclaración se considera segura.

Barmak Shemirani
fuente
1
Escribe "Los miembros en clases de C ++ están protegidos de forma predeterminada". Según el estándar, son privados o públicos por defecto, dependiendo de qué palabra clave se utilizó en la definición (14p3). ¿Microsoft se desvía del estándar aquí?
Alexander Klauer
@AlexanderKlauer Me equivoqué, es privatepor defecto en Visual Studio. También está privatepor defecto en gcc, nunca está publicpor defecto. A menos que me vuelva a equivocar. No puedo encontrar el estándar al que te refieres.
Barmak Shemirani
Lo siento, debería haber sido más específico. Me refería al estándar C ++ 17. El estándar C ++ 11 tiene la misma redacción en 11p3. ¿Podrías actualizar tu respuesta? ¡Gracias!
Alexander Klauer
1

Solo se puede acceder al miembro privado en la misma clase donde ha declarado donde se puede acceder como miembro protegido en la clase donde se declara junto con las clases que hereda.

Gayki
fuente
1
  • Privado : es un especificador de acceso. Por defecto, las variables de instancia (miembro) o los métodos de una clase en c ++ / java son privados. Durante la herencia, el código y los datos siempre se heredan pero no es accesible fuera de la clase. Podemos declarar a nuestros miembros de datos como privados para que nadie pueda hacer cambios directos a nuestras variables de miembro y podemos proporcionar captadores y establecedores públicos para cambiar nuestros miembros privados. Y este concepto siempre se aplica en la regla de negocios.

  • Protegido : también es un especificador de acceso. En C ++, los miembros protegidos son accesibles dentro de la clase y para la clase heredada pero no fuera de la clase. En Java, los miembros protegidos son accesibles dentro de la clase, tanto para la clase heredada como para todas las clases dentro del mismo paquete.

Tutu Kumari
fuente
0

Los miembros y amigos de cualquier clase derivada de esa clase base pueden acceder a un miembro de clase base no estático protegido utilizando uno de los siguientes:

  • Un puntero a una clase derivada directa o indirectamente
  • Una referencia a una clase derivada directa o indirectamente
  • Un objeto de una clase derivada directa o indirectamente.
mujtaba
fuente
0

Privado: Accesible por funciones de miembro de clase y función de amigo o clase de amigo. Para la clase C ++, este es el especificador de acceso predeterminado.

Protegido: Accesible por funciones de miembro de clase, función de amigo o clase de amigo y clases derivadas.

  • Puede mantener la variable o función de miembro de clase (incluso typedefs o clases internas) como privadas o protegidas según sus requisitos.
  • La mayoría de las veces mantiene al miembro de la clase como privado y agrega funciones get / set para encapsular. Esto ayuda en el mantenimiento del código.
  • En general, la función privada se usa cuando desea mantener sus funciones públicas modulares o eliminar el código repetido en lugar de escribir código completo en una sola función. Esto ayuda en el mantenimiento del código.

Consulte este enlace para más detalles.

Darshan Rajgor
fuente
-2

Los modificadores de acceso privado y protegido son uno y el mismo solo que se puede acceder a los miembros protegidos de la clase base fuera del alcance de la clase base en la clase secundaria (derivada). También se aplica lo mismo a la herencia. Pero con el modificador privado solo se puede acceder a los miembros de la clase base en el ámbito o código de la clase base y sus funciones de amigo solo '' ''

Emmanuel Muniko
fuente
55
¿Qué valor agrega su respuesta sobre las otras respuestas?
Hermann Döppes