À mon avis, les réponses existantes n'expliquent pas bien le "pourquoi" de cette situation - elles se concentrent trop sur la réitération des comportements valides. "Les modificateurs d'accès fonctionnent au niveau de la classe, et non au niveau de l'objet". - oui, mais pourquoi ?
Le concept général ici est que c'est le(s) programmeur(s) qui conçoit, écrit et maintient une classe qui est (sont) censé(s) comprendre l'encapsulation OO souhaitée et être habilité(s) à coordonner sa mise en œuvre. Donc, si vous écrivez class X
vous n'encodez pas seulement la façon dont un individu X x
peut être utilisé par le code qui y a accès, mais aussi comment :
- les classes dérivées sont en mesure d'interagir avec elle (par le biais de fonctions virtuelles pures et/ou d'un accès protégé), et
- distinct
X
objets coopérer pour fournir les comportements voulus tout en respectant les post-conditions et les invariants de votre conception.
Il n'y a pas que le constructeur de copie - un grand nombre d'opérations peuvent impliquer deux ou plusieurs instances de votre classe : si vous comparez, ajoutez/multipliez/divisez, construisez par copie, clonez, assignez, etc., il est fréquent que vous deviez avoir accès à des données privées et/ou protégées dans l'autre objet, ou que vous vouliez permettre une implémentation de fonction plus simple, plus rapide ou généralement meilleure.
Plus précisément, ces opérations peuvent vouloir profiter d'un accès privilégié pour faire des choses comme.. :
- (constructeurs de copie) utilisent un membre privé de l'objet "rhs" (right hand side) dans une liste d'initialisation, de sorte qu'une variable membre est elle-même construite par copie au lieu d'être construite par défaut (si c'est légal) puis assignée (encore une fois, si c'est légal)
- partager les ressources - poignées de fichiers, segments de mémoire partagée,
shared_ptr
aux données de référence, etc.
- s'approprier les choses, par exemple
auto_ptr<>
"déplace" la propriété vers l'objet en construction
- copier les membres privés du "cache", de l'étalonnage ou de l'état nécessaires à la construction du nouvel objet dans un état d'utilisation optimale sans devoir les régénérer à partir de zéro.
- copier/accéder à des informations de diagnostic/trace conservées dans l'objet copié, qui ne sont pas autrement accessibles par les API publiques mais qui pourraient être utilisées par un objet d'exception ou une journalisation ultérieure (par exemple, quelque chose sur le moment/les circonstances où l'instance "originale" non copiée a été construite)
- effectuer une copie plus efficace de certaines données : par exemple, les objets peuvent avoir par exemple une
unordered_map
mais n'exposent publiquement que begin()
y end()
itérateurs - avec un accès direct aux size()
vous pourriez reserve
pour une copie plus rapide ; pire encore, s'ils ne font qu'exposer at()
y insert()
et sinon throw
....
- recopier les références aux objets parents/coordination/gestion qui peuvent être inconnus ou en écriture seule pour le code client.