En mi humilde opinión, las respuestas existentes no hacen un buen trabajo al explicar el "por qué" de esto, centrándose demasiado en reiterar qué comportamiento es válido. "Los modificadores de acceso funcionan a nivel de clase y no a nivel de objeto". - ¿si, pero por qué?
El concepto general aquí es que son los programadores que diseñan, escriben y mantienen una clase los que se espera que comprendan la encapsulación OO deseada y estén capacitados para coordinar su implementación. Entonces, si está escribiendo class X
, está codificando no solo cómo un X x
objeto individual puede ser utilizado por código con acceso a él, sino también cómo:
- las clases derivadas pueden interactuar con él (a través de funciones virtuales puras opcionalmente y / o acceso protegido), y
- los
X
objetos distintos cooperan para proporcionar comportamientos previstos mientras respetan las condiciones posteriores y las invariantes de su diseño.
Tampoco es solo el constructor de copia; muchas operaciones pueden involucrar dos o más instancias de su clase: si está comparando, sumando / multiplicando / dividiendo, copiando-construyendo, clonando, asignando, etc., entonces a menudo es el caso que usted o simplemente debe tener acceso a datos privados y / o protegidos en el otro objeto, o quiere que permita una implementación de función más simple, rápida o generalmente mejor.
Específicamente, estas operaciones pueden querer aprovechar el acceso privilegiado para hacer cosas como:
- (constructores de copia) usan un miembro privado del objeto "rhs" (lado derecho) en una lista de inicializador, de modo que una variable miembro se construye con copia en lugar de construirse por defecto (si es que es legal) y luego se asigna también (nuevamente, si es legal)
- recursos compartidos: identificadores de archivos, segmentos de memoria compartida,
shared_ptr
s para datos de referencia, etc.
- tomar posesión de las cosas, por ejemplo
auto_ptr<>
"traslada" la propiedad al objeto en construcción
- copiar "caché" privado, calibración o miembros de estado necesarios para construir el nuevo objeto en un estado de uso óptimo sin tener que regenerarlos desde cero
- copiar / acceder a la información de diagnóstico / seguimiento que se mantiene en el objeto que se está copiando que no es accesible de otra manera a través de API públicas, pero que podría ser utilizada por algún objeto de excepción o registro posterior (por ejemplo, algo sobre el tiempo / circunstancias en que la instancia "original" no construida por copia fue construido)
- realizar una copia más eficiente de algunos datos: p. ej., los objetos pueden tener, p. ej., un
unordered_map
miembro pero solo exponer begin()
e end()
iteradores públicamente - con acceso directo a size()
su reserve
capacidad de copia más rápida; peor aún si solo exponen at()
y insert()
y de lo contrario throw
....
- copiar referencias a objetos principales / de coordinación / administración que pueden ser desconocidos o de solo escritura para el código del cliente