next up previous contents
Next: Static components Up: Data encapsulation with classes Previous: Classes   Contents

Data encapsulation (public and private)

What is the status of the instance variables defined within a class? It seems desirable that these variables should not be accessible externally. For instance, there should be no way to use the variables s and t of type stack to directly manipulate the contents of tos and the array value within s and t. For, if these internal variables are accessible externally, we once again have to deal with the problem of maintaining the integrity of our abstract data type!

One way to achieve total data integrity is to make all internal data variable inaccessible from outside. Of course, there is almost always a requirement to be able to access the values of some or all of the variables and also modify or update them--for example, consider the following definition:

   class date {
      int day, month, year;
   }

where one might reasonably expect to be able to find out what date is currently stored, as well as, perhaps, to reset the date to a fresh value.

To meet this requirement while keeping internal variables inaccessible, we could write functions like get_date() and set_date(...) that provide limited, controlled access to the data stored in the class. (Note: In object-oriented jargon, a method that reads the values of internal variables, like get_date(), is called an accessor method and a method that updates the values of internal variables, like set_date(...) is called a mutator method.) Using appropriate accessor and mutator functions, we can control very precisely the degree to which the data in the stack can be manipulated externally.

However, probably to accommodate lazy programmers, most object-oriented languages do permit direct external access to variables. The syntax is similar to that for accessing members of structures in C (or fields of records in Pascal). For example, the field tos in the stack s is designated s.tos, so we can write code like:

   if (s.tos == 0){ ... }

Once we permit this facility, we have to introduce an additional mechanism to prevent misuse--that is, to retain data integrity. This is typically done by adding the qualifiers public and private to each variable defined in a class. As should be clear, a variable that is declared to be public is accessible from outside while one that is declared private is not. One would write

  class stack{
    private int values[100];
    private int tos = 0;
    ...
  }

to ensure that the only way to access the stack is via push, pop and is_empty. Of course, private only refers to the external world: the functions within the class like push, pop and is_empty have full access to all the data variables defined in the class.

What about methods--should all methods be accessible by default? Suppose our language has a mechanism to request storage at run-time (like the malloc function in C). We might then incorporate a method extend_stack into our class and use it when the stack becomes full:

  class stack {
    ...
    push (int i){    /* push i onto stack */
      if (stack_full){
        extend_stack();
      }
      ...            /* Code to add i to stack * /
    }

    extend_stack(){
      ...  /* Code to get additional space for stack data */
    }
    ...
  }

Clearly extend_stack is an implementation detail that is not intended to be revealed outside the class. It would make sense to extend the use of the attributes public and private to methods as well, making, in this case, only the methods push, pop and is_empty public and all other methods, including extend_stack, private.


next up previous contents
Next: Static components Up: Data encapsulation with classes Previous: Classes   Contents
Madhavan Mukund 2004-04-29