104

I have learned that I can never access a private variable, only with a get-function in the class. But then why can I access it in the copy constructor?

Example:

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);
}

My declaration:

private:
  T *pFirst,*pLast,*pEnd;
demonking
  • 2,584
  • 5
  • 23
  • 28

6 Answers6

128

The access modifiers work on class level, and not on object level.

That is, two objects of the same class can access each others private data.

Why:

Primarily due to efficiency. It would be a non-negligible runtime overhead to check if this == other each time you access other.x which you would have to if the access modifiers worked on object level.

It's also kind of semantically logical if you think of it in terms of scoping: "How big part of the code do I need to keep in mind when modifying a private variable?" – You need to keep the code of the whole class in mind, and this is orthogonal to which objects exist in runtime.

And it's incredibly convenient when writing copy constructors and assignment operators.

aioobe
  • 413,195
  • 112
  • 811
  • 826
  • Re: "It would be a non-negligible runtime overhead to check if `this == other` ": I think this check could always be done at compile time. I would like it much better, if access was on object level, not class level. – Eike Nov 09 '21 at 10:57
  • Would you like this to compile `other = Math.random() > 0.5 ? this : somethingElse; print(other.privateField);`? – aioobe Nov 09 '21 at 13:45
  • I have no idea, what it does, care to explain? – Eike Nov 10 '21 at 13:28
  • It accesses a private field on a randomly selected object. The selected object is either `this` or a reference called `somethingElse`. – aioobe Nov 10 '21 at 20:40
  • I see. No, I don't think, I would like that to compile. I understand that it is virtually impossible to change this behaviour in C++ because the standard was written including this behaviour so god knows what would break in case this was changed. I'm just saying, that this behaviour surprised me tremendously when I wrote my first copy constructor and I like the object level privacy better because then I can be sure that really noone but `this` can change the variable. – Eike Nov 11 '21 at 12:41
  • Ok. Well, right, the semantics are not going to change obviously. I'm just curious how people that would like access modifiers to work on object level expect this to be implemented under the hood without sprinkling the code with runtime checks. Would you like this to compile: `other = this; print(other.privateField);` for example? – aioobe Nov 11 '21 at 15:41
  • If its in the same translation unit, yes. But I think that could be a compile time check, would it not? – Eike Nov 11 '21 at 22:07
  • Or probably rather no. Easiest implementation would, i guess, be to allow private access only to this. – Eike Nov 11 '21 at 22:19
  • Ah, I now see a real problem with my approach. At least the copy constructor and the assignment operator must access private members. So to implement this object-level access there would have to be special rules for these methods, which is more difficult to grasp than a clean rule. – Eike Nov 12 '21 at 07:34
43

IMHO, existing answers do a poor job explaining the "Why" of this - focusing too much on reiterating what behaviour's valid. "access modifiers work on class level, and not on object level." - yes, but why?

The overarching concept here is that it's the programmer(s) designing, writing and maintaining a class who is(are) expected to understand the OO encapsulation desired and empowered to coordinate its implementation. So, if you're writing class X, you're encoding not just how an individual X x object can be used by code with access to it, but also how:

  • derived classes are able to interact with it (through optionally-pure virtual functions and/or protected access), and
  • distinct X objects cooperate to provide intended behaviours while honouring the post-conditions and invariants from your design.

It's not just the copy constructor either - a great many operations can involve two or more instances of your class: if you're comparing, adding/multiplying/dividing, copy-constructing, cloning, assigning etc. then it's often the case that you either simply must have access to private and/or protected data in the other object, or want it to allow a simpler, faster or generally better function implementation.

Specifically, these operations may want to take advantage of priviledged access to do things like:

  • (copy constructors) use a private member of the "rhs" (right hand side) object in an initialiser list, so that a member variable is itself copy-constructed instead of default-constructed (if even legal) then assigned too (again, if legal)
  • share resources - file handles, shared memory segments, shared_ptrs to reference data etc.
  • take ownership of things, e.g. auto_ptr<> "moves" ownership to the object under construction
  • copy private "cache", calibration, or state members needed to construct the new object in an optimally usable state without having to regenerate them from scratch
  • copy/access diagnostic/trace information kept in the object being copied that's not otherwise accessible through public APIs but might be used by some later exception object or logging (e.g. something about the time/circumstances when the "original" non-copy-constructed instance was constructed)
  • perform a more efficient copy of some data: e.g. objects may have e.g. an unordered_map member but publicly only expose begin() and end() iterators - with direct access to size() you could reserve capacity for faster copying; worse still if they only expose at() and insert() and otherwise throw....
  • copy references back to parent/coordination/management objects that might be unknown or write-only for the client code
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • 2
    I think the biggest 'why' is that it would be a tremendous runtime overhead to check if `this == other` each time you access `other.x` which you would have to if the access modifiers worked on object level. – aioobe Jul 13 '16 at 18:58
  • 2
    @aioobe I think your answer should be way, way more prominent. Whilel Tony's answer is really good and conceptual, if I were a betting man, I would bet that your answer is the actual historical reason for the choice. Not only is it more performant, but it's also much simpler. Would be a great question for Bjarne! – Nir Friedman Apr 04 '17 at 16:26
  • I have marked your answer, because it explains the background ;) – demonking Jun 29 '17 at 13:58
  • @demonking, I think the reasons given in this answer covers why it's *convenient* to let the private data be open to other objects. But access modifiers aren't meant to make data "openly" enough. They are rather meant to make data *closed* enough for encapsulation. (In terms of *convenience* it would be even *better* if private variables where public!) I updated my answer with a section which I think better addresses the actual *why*. – aioobe Jun 29 '17 at 23:05
  • @aioobe: old comments, but anyway... "check if `this == other` each time you access `other.x`" - misses the point - if `other.x` was only accepted at runtime when equivalent to `this.x`, there wouldn't be much pointer writing `other.x` in the first place; the compiler might as well force you to write `if (this == other) ...this.x...` for whatever you were going to do. Your *"convenience (even more if private variables were public)"* conception also misses the point - the way the Standard's defined is restrictive enough to allow *proper* encapsulation, but not unnecessarily inconvenient. – Tony Delroy Feb 06 '18 at 11:15
36

You can access private members of a class from within the class, even those of another instance.

Alexander Rafferty
  • 6,134
  • 4
  • 33
  • 55
11

To understand the answer, I would like to remind you few concepts.

  1. No matter how many objects you create, there is only one copy of one function in memory for that class. It means functions are created only once. However variables are separate for each instance of the class.
  2. this pointer is passed to every function when called.

Now it's because of the this pointer, function is able to locate variables of that particular instance. no matter if it is private of public. it can be accessed inside that function. Now if we pass a pointer to another object of the same class. using this second pointer we will be able to access private members.

Hope this answers your question.

Pavel
  • 7,436
  • 2
  • 29
  • 42
Ali Zaib
  • 127
  • 1
  • 2
7

Copy constructor is class' member function and as such has access to class' data members, even those declared as 'private'.

Bojan Komazec
  • 9,216
  • 2
  • 41
  • 51
  • 5
    As someone who knows the language, I understand what you mean. However, if I didn't know the language, I would have thought that you were just repeating the question back to me. – San Jacinto Nov 07 '10 at 20:45
1

why the man who made that compiler allow this behavior, that we can see hidden members of an object (that its type is the same of the class where you access the hidden members) in copy constructor or in any method in the class.

The answer: because you when you are in the class that's mean you are the builder or the designer of the class also mean that you know all data members and methods in that class that's why he allow this behavior because you build this class you know every thing about it unlike the users of the class they haven't to know every thing about the class like you.

the idea of hiding data members or method that help the users of this class and not confused them with non important things.

That's it.

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 28 '21 at 09:13