Encapsulation and Public Interfaces
The read_and_sum() function is a client of the Vector class: it creates a Vector, reads and writes its elements, and asks for its size, all through public members.
A Function That Only Talks to an Object
Writing a class is only half of the work. The other half is using it. This article looks at a short function, read_and_sum(), that makes use of a Vector class. Its job is to read a number of values, store them, and return their total. The function is simple enough to follow line by line, which makes it a good place to see how a program talks to an object.
As you read, pay attention to one question: which parts of the Vector object does the function actually need to know about? The answer shapes the whole idea of encapsulation, which this article explains.
What do you think happens?
Before reading the function, guess which members of Vector the function must name directly in its code. Choose from: the constructor, operator[], size(), elem, and sz.
Reveal answer
Only the constructor, operator[], and size()
The function creates the object with Vector v(s), reads and writes elements with v[i], and asks for the count with v.size(). It never names elem or sz. Those two members are the hidden representation of the class, and the function works only through the public members.
The Function Being Traced
The source describes read_and_sum() in terms of what it does and how it uses the Vector: it creates one with Vector v(s), it reads and writes its elements with v[i], and it asks how many elements it holds with v.size(). The source does not print the full function, so the listing below is a reconstruction written to match those uses exactly. Treat it as a teaching sketch, not as the original text. The return type double is an assumption made for this sketch.
- Vector v(s) creates the object with s elements, using the constructor in the public interface.
- The first loop reads values from input into v[i], using operator[] for access.
- The loop test i !=
v.size()usessize()as the stopping point. - The second loop uses the same test and the same access form v[i] to add the elements into sum.
- Nothing in the function names elem or sz.
Notice that the two loops are nearly identical. They use the same stopping test, i != v.size(), and the same access form, v[i]. The source points out that this repetition is not an accident of style. Both loops depend on the same public interface.
Tracing the Calls Step by Step
The diagram below shows the same function as a sequence of messages between the function and the Vector object. Read it from top to bottom. Each arrow is one interaction, and each one uses a public member.
Step 1 creates the object. The declaration Vector v(s) uses the constructor, and the object is created with s elements. Steps 2 and 3 belong to the first loop: each pass checks the stopping test with size() and then stores a value through v[i]. Steps 4 and 5 belong to the second loop, which checks size() again and reads each element through v[i] to build the total. At no point does the function touch the object's storage by name.
Tracing read_and_sum(3) with inputs 4, 5, and 6
The function is called with s equal to 3, and the user types the values 4, 5, and 6. What does the function return?
- 1Create the object
Vector v(3) creates a Vector with 3 elements. The loop test will compare i against
v.size(), which is 3. - 2First loop, reading
When i is 0, cin >> v[0] stores 4. When i is 1, cin >> v[1] stores 5. When i is 2, cin >> v[2] stores 6. Then i becomes 3, and the test i !=
v.size()fails, so the loop stops. - 3Second loop, summing
sum starts at 0. The loop adds v[0] (4), then v[1] (5), then v[2] (6), giving 0 + 4 + 5 + 6.
- 4Return
The function returns the total, which is 15.
The function returns 15. Each access went through v[i] and each stopping test went through v.size(), so the function never needed to know how the values are stored.
The Public Interface and the Hidden Representation
The class interface is the set of public members that clients may use. For Vector, these are Vector(), operator[](), and size(). Encapsulation is the idea that the representation, the members elem and sz, is hidden from the outside, so that a Vector can only be worked with through its interface.
The diagram separates the two sides of the class. On one side is the interface, the three members a client may call. On the other side is the representation, the members elem and sz, which the source says are accessible only through that interface. The read_and_sum() function sits entirely on the interface side.
The consequence is that the client depends on what the object does, not on how it stores its data. The source makes this the point of the design: if the object's internals changed while the interface stayed the same, the two loops in read_and_sum() would not need to change.
Why the Client Stays on the Outside
It is tempting to reach into an object and touch its members directly, because the members are right there. The source's design says not to. Consider what would change for the client if it touched elem and sz directly instead of going through operator[] and size(). The table compares the two approaches.
| Question | Client uses operator[] and size() | Client touches elem and sz directly |
|---|---|---|
| Which members does the client name? | Vector(), operator[](), size() | elem and sz, the hidden representation |
| What can the class change without breaking the client? | Its internal storage, as long as the interface stays the same | Very little, because the client now depends on the storage layout |
| Where does the client's code belong? | On the interface side of the boundary | Across the boundary, inside the object's private details |
| Does the loop test still come from the object? | Yes, through size() | Only if the client recomputes it from sz itself |
Client access through the public interface compared with direct access to the hidden representation
Where a Wrong Result Comes From
When a function that uses a class returns a wrong total, the fault is usually in one of the places where the client meets the object. The diagram follows a value from input through the Vector's storage to the returned sum. Each arrow is a place where a mistake can enter.
Common mistake Creating the Vector with the wrong size
What it looks likeCalling read_and_sum(2) when the user is going to type three values.
Why it failsVector(s) sets how many elements the object holds, and the loops stop at
size(). The extra input is never stored.Do this insteadMake sure the size passed to the constructor matches the number of values the function is meant to read.
Common mistake Indexing outside the valid range
What it looks likeWriting a loop that goes one step past the last element, so that v[i] is used with i equal to the size.
Why it failsThe client is responsible for indexing the object within range. An out-of-range index is a client error, even though the Vector itself is written correctly.
Do this insteadKeep the loop test as i != v.size() so that the index stops before leaving the valid range.
Common mistake Looking inside the object to debug it
What it looks likePrinting elem or sz to check the result before checking the function's own calls.
Why it failsThese members are the hidden representation. Inspecting them skips the interface, which is where the client's mistake is most likely to be.
Do this insteadCheck the client's use of the public interface first, then check the class itself.
When a class-using function misbehaves, separate the client code from the object. First ask whether the client calls the public interface correctly: does it create the object with the right size, index it within range, and use size() to control its loops? Only after that should you consider whether the class itself is at fault.
Practice Tracing a Call
Suppose read_and_sum(2) is called and the user types 7, 8, and 9 in that order. Trace the two loops and state the value the function returns. Then say which line is the first place a client mistake would show up.
Hints
- Vector v(2) creates an object with 2 elements, so the loop test stops after two reads.
- The extra value 9 is never read into an element of v.
- Work out the sum using only the two values that were stored.
Key Takeaways
read_and_sum()is a client of Vector: it creates the object with Vector v(s), reads and writes elements with v[i], and asks for the count withv.size().- The public interface,
Vector(), operator[](), andsize(), is what clients may use. The representation, elem and sz, is hidden by encapsulation. - Because the client depends only on the interface, the class's internals could change without requiring changes to the loops in the client.
- When a class-using function returns a wrong result, check the client's use of the public interface first, including the size passed to the constructor, the indexing range, and the loop test, and only then check the class itself.