It
is helpful to break up the playing field into
class
creators
(those who create new data types) and
client
programmers
[9]
(the class consumers who use the data types in their applications). The goal of
the client programmer is to collect a toolbox full of classes to use for rapid
application development. The goal of the class creator is to build a class that
exposes only what’s necessary to the client programmer and keeps
everything else hidden. Why? Because if it’s hidden, the client
programmer can’t use it, which means that the class creator can change
the hidden portion at will without worrying about the impact to anyone else.
The hidden portions usually represent the tender insides of an object that
could easily be corrupted by a careless or uninformed client programmer, so
hiding the implementation reduces program bugs. The concept of implementation
hiding cannot be overemphasized.
In
any relationship it’s important to have boundaries that are respected by
all parties involved. When you create a library, you establish a relationship
with the client
programmer,
who is also a programmer, but one who is putting together an application by
using your library, possibly to build a bigger library.
If
all the members of a class are available to everyone, then the client
programmer can do anything with that class and there’s no way to enforce
any rules. Even though you might really prefer that the client programmer not
directly manipulate some of the members of your class, without access control
there’s no way to prevent it. Everything’s naked to the world.
So
the first reason for access control is to keep client programmers’ hands
off portions they shouldn’t touch – parts that are necessary for
the internal machinations of the data type but not part of the interface that
users need to solve their particular problems. This is actually a service to
users because they can easily see what’s important to them and what they
can ignore.
The
second reason for access control is to allow the library designer to change the
internal workings of the class without worrying about how it will affect the
client programmer. For example, you might implement a particular class in a
simple fashion to ease development, and then later discover you need to rewrite
it in order to make it run faster. If the interface and implementation are
clearly separated and protected, you can easily accomplish this and require
only a relink by the user.
C++
uses three explicit keywords to set the boundaries in a class:
public,
private,
protected.
Their use and meaning are quite straightforward. These
access
specifiers
determine
who can use the definitions that follow.
publicmeans
the following definitions are available to everyone. The
privatekeyword,
on the other hand, means that no one can access those definitions except you,
the creator of the type, inside function members of that type.
private
is a brick wall between you and the client programmer. If someone tries to
access a
private
member, they’ll get a compile-time error.
protected
acts just like
private,
with the exception that an inheriting class has access to
protected
members, but not
private
members. Inheritance will be introduced shortly.
[9]
I’m indebted to my friend Scott Meyers for this term.