web-dev-qa-db-fra.com

Pourquoi puis-je accéder aux variables privées dans le constructeur de copie?

J'ai appris que je ne peux jamais accéder à une variable privée, uniquement avec une fonction get dans la classe. Mais alors pourquoi puis-je y accéder dans le constructeur de copie?

Exemple:

Field::Field(const Field& f)
{
  pFirst = new T[f.capacity()];

  pLast = pFirst + (f.pLast - f.pFirst);
  pEnd  = pFirst + (f.pEnd - f.pFirst);
  std::copy(f.pFirst, f.pLast, pFirst);
}

Ma déclaration:

private:
  T *pFirst,*pLast,*pEnd;
76
demonking

À mon humble avis, les réponses existantes expliquent mal le "pourquoi" de cela - en se concentrant trop sur la réitération de ce comportement valide. "les modificateurs d'accès fonctionnent au niveau de la classe et non au niveau de l'objet." - Oui mais pourquoi?

Le concept global ici est que c'est le ou les programmeurs qui conçoivent, écrivent et maintiennent une classe qui sont censés comprendre l'encapsulation OO souhaitée et habilitée à coordonner son implémentation. Donc, si vous écrivez class X, vous encodez non seulement comment un objet X x individuel peut être utilisé par du code avec accès, mais aussi comment:

  • les classes dérivées sont capables d'interagir avec lui (grâce à des fonctions virtuelles éventuellement pures et/ou un accès protégé), et
  • objets X distincts coopérer pour fournir les comportements voulus tout en respectant les post-conditions et les invariants de votre conception.

Ce n'est pas seulement le constructeur de copie non plus - un grand nombre d'opérations peuvent impliquer deux instances ou plus de votre classe: si vous comparez, ajoutez/multipliez/divisez, copiez-construisez, clonez, attribuez etc., alors c'est souvent le cas que vous soit doit simplement avoir accès à des données privées et/ou protégées dans l'autre objet, soit vouloir qu'il permette 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" (côté droit) dans une liste d'initialisation, de sorte qu'une variable membre est elle-même construite en copie au lieu de construction par défaut (si elle est même légale) puis affectée également (encore une fois, si légal)
  • partager des ressources - descripteurs de fichiers, segments de mémoire partagée, shared_ptr pour référencer des données, etc.
  • prendre possession des choses, par ex. auto_ptr<> "Déplace" la propriété vers l'objet en construction
  • copier le "cache" privé, l'étalonnage ou les membres d'état nécessaires pour construire le nouvel objet dans un état utilisable de manière optimale sans avoir à les régénérer à partir de zéro
  • copier/accéder aux informations de diagnostic/trace conservées dans l'objet en cours de copie qui ne sont pas autrement accessibles via les API publiques, mais qui pourraient être utilisées par un objet d'exception ou une journalisation ultérieurs (par exemple, quelque chose sur l'heure/les circonstances où l'instance "d'origine" non construite en copie) a été construit)
  • effectuer une copie plus efficace de certaines données: par ex. les objets peuvent avoir par exemple un membre unordered_map mais n'expose publiquement que les itérateurs begin() et end() - avec un accès direct à size() vous pourriez reserve capacité pour copie plus rapide; pire encore s'ils n'exposent que at() et insert() et sinon throw....
  • copier les références vers les objets parent/coordination/gestion qui peuvent être inconnues ou en écriture seule pour le code client
28
Tony Delroy

Les modificateurs d'accès fonctionnent sur niveau classe, et non sur niveau objet.

Autrement dit, deux objets de la même classe peuvent accéder l'un à l'autre aux données privées.

Pourquoi:

Principalement en raison de l'efficacité. Ce serait un temps d'exécution non négligeable pour vérifier si this == other chaque fois que vous accédez à other.x ce que vous auriez à faire si les modificateurs d'accès fonctionnaient au niveau de l'objet.

C'est aussi un peu sémantiquement logique si vous y pensez en termes de portée: "Quelle partie du code dois-je garder à l'esprit lors de la modification d'une variable privée?" - Vous devez garder à l'esprit le code de toute la classe, et c'est orthogonal aux objets qui existent en runtime.

Et c'est incroyablement pratique lors de l'écriture de constructeurs de copie et d'opérateurs d'affectation.

104
aioobe

Vous pouvez accéder aux membres privés d'une classe depuis la classe, même ceux d'une autre instance.

33

Pour comprendre la réponse, je voudrais vous rappeler quelques notions.

  1. Peu importe le nombre d'objets que vous créez, il n'y a qu'une seule copie d'une fonction en mémoire pour cette classe. Cela signifie que les fonctions ne sont créées qu'une seule fois. Cependant, les variables sont distinctes pour chaque instance de la classe.
  2. this le pointeur est passé à chaque fonction lors de son appel.

Maintenant, c'est à cause du pointeur this, la fonction est capable de localiser les variables de cette instance particulière. peu importe si elle est privée ou publique. il est accessible à l'intérieur de cette fonction. Maintenant, si nous passons un pointeur vers un autre objet de la même classe. en utilisant ce deuxième pointeur, nous pourrons accéder aux membres privés.

J'espère que ça répond à ta question.

11
Ali Zaib

Le constructeur de copie est une fonction membre de la classe et, en tant que tel, a accès aux membres de données de la classe, même ceux déclarés comme "privés".

6
Bojan Komazec