3.1 Using Objects for Communication
An object-oriented system is an organized group of interacting objects forming associations and aggregations. Each object in the system performs a specialized role and communicates with other objects as needed to perform its role as an individual and as a collaborating member of a larger assembly. The interacting objects may be of different classes or of the same class. When the interacting objects are of different classes, the definition of one class must refer to objects of another class. When the objects are in the same class, the definition of the class must refer to itself in some way.
Objects that interact with one another often use other objects to communicate information among themselves. The object used for the communication is generated by a sender object and is made available to a receiver object. The communication may be unidirectional (from sender to receiver) or bidirectional (information supplied by the sender is modified by the receiver and returned to the sender). The communication may also be structured so that it is short-lived (relevant only during the immediate method invocation) or more prolonged (a shared object is used to allow interaction over an interval of time longer than the immediate method invocaton).
There are three ways in which objects can be used to communicate information:
It is primarily the last two techniques, parameter passing and return value, that will be examined in more detail.
A method that receives an object as a parameter or returns an object as its result specifies how that parameter object can be manipulated by the method and how the return result can be manipulated. The specification defines the answer to four important questions about the parameter or result object:
The table below summarizes the various techniques that are used and what answers each provides to these questions.
Passing an object by copy (also known as "by value") has this name because a copy of the object is made and the copy is passed to the receiver. Passing an object by copy is appropriate when the sender wants to be sure that any actions taken by the receiver do not change the object from the sender's perspective. This is a safe form of passing information that is meant to be consumed by the receiver. In effect, a unidirectional form of communication is provided via the by copy semantics.
Passing an object by copy is not appropriate in three situations. First, if the passed object is to be shared between the sender and the receiver, passing the object by copy results in the sender and the receiver operating on different copies of an object, not a single, shared object. An example of sharing will be seen below. Second, if the sender wants the receiver to modify the passed object, then the object itself, and not a copy of it, must be passed. Third, very large objects (e.g., a 1-megabyte bitmapped image object) are typically not passed by copy to avoid the overhead in memory usage and copying time. However, these cases must be carefully handled to guard against unintended modifications made by the called code.
Passing objects by reference or by pointer communicates the identity of the object being passed instead of a copy of the object. Passing an object by reference or by pointer avoids the cost of copying the object and allows the sender and receiver to share the same object. In the simple form, passing objects by reference or by pointer also allows the sender to observe any changes that the receiver might make in the shared object. Often, observing these changes is how the communication between the sender and the receiver is achieved. In other cases it is desired that the object be protected against change by the receiver.
The const reference and const pointer forms of passing an object provide a way to avoid copying the object (as with the simpler by reference and by pointer) without allowing the receiver to change the passed object. The "const" attribute is short for "constant," meaning that the reciever is limited to using only those methods of the const object that are known by the compiler not to change the object. Thus, the receiver can use accessor methods to query or interrograte the object but cannot use mutator methods that change the state of the object. Methods that are declared as not changing the state of an object are called const methods.