Making a class's member variables private leads to stronger encapsulation, preventing client code from inadvertently changing or inappropriately relying on them. However, clients may have a legitimate need to retrieve or update private data stored in an object. For example, if the client program uses instances of the Person class, it may need to get the names from the objects or update their addresses when they move. Programmers could satisfy legitimate access needs by making some data public, but doing so would sacrifice encapsulation, exposing the data to both legitimate and illegitimate use. Getter and setter functions (collectively referred to as access functions) satisfy the client's legitimate need to access private data while maintaining encapsulation, and the security offered by the private specification.
| Member Variable | Getter Prototypes | Naming Conventions |
|---|---|---|
int age; |
int get_age();int getAge(); |
|
string name; |
string get_name();string getName(); |
const pointer or references (covered in detail later in the chapter).
| Member Variable | Setter Prototypes | Naming Conventions |
|---|---|---|
int age; |
void set_age(int);void setAge(int); |
|
string name; |
void set_name(string);void setName(string); |
public members without restriction, setters allow class developers to maintain some control over access. Setters may include validity checks, such as ensuring that a person's height or age is non-negative but doesn't exceed a maximum amount. In the case of strings, they can verify that a name has at least one character or reject invalid dates such as "February 31." Setters can also reformat data to match a standard format. For example, if the standard format for a birthday is "1960/12/25," but the user enters the date as "Dec 25, 1960," the setter can reformat the date to match the standard before saving it.
Class developers are not obligated to provide getters and setters for all member variables, but when they do, the functions become a part of the class's public interface. Access functions maintain the separation between the class's implementation and how clients use objects instantiated from it. The following examples demonstrate getters and setters, and how they separate access from implementation.
class Person
{
private:
string name;
int age;
public:
string get_name()
{
return name;
}
int get_age()
{
return age;
}
void set_name(string n)
{
if (n.length() > 0 && n.length() < 35)
name = n;
}
void set_age(int a_age)
{
if (age >= 0 && age < 115)
age = a_age;
}
};
![]() |
![]() |
void push(char); char pop(); int size(); |
| (a) | (b) | (c) |
The main function plays the role of the client in each example. The stack examples utilize simple exception handling, which the text formally introduces later in the chapter.
| View | Download | Comments |
|---|---|---|
| access.cpp | access.cpp | Demonstrates two setters and two getters. Although the members and their types change, the basic access function patterns remain unchanged. The example also demonstrates that when the client changes a value returned by a getter, the object's stored value remains unchanged. |
| stack1.cpp | stack1.cpp | A character stack implemented as an array and a stack pointer. |
| A character stack implemented as a linked list. The top node is a list head that simplifies the push and pop operations by removing the boundary conditions encountered when pushing the first element on the stack or popping the last one off. As such, it does not store data. | ||
| stack2.cpp | stack2.cpp | The size function counts the list nodes each time the program calls it. Although inefficient for large stacks, it demonstrates how separating the data structure's implementation from its interface allows developers to significantly change the implementation without affecting client code. |
| stack3.cpp | stack3.cpp | The stack class counts the nodes as they are pushed on or popped off the stack; the size returns the count. |
Aside from demonstrating that the array and linked list versions of the stack class can organize and access the stored data in different ways while providing identical interfaces, the actual implementations are irrelevant to the goals of this section. However, for the interested reader, the following figure details the pointer manipulations in the linked-list version of the push operation.
![]() |
Each stack node consists of two fields: data and a pointer, down, linking the nodes. | ||
| Initial | node* temp = new node; temp->data = c; |
temp->down = top->down; | top->down = temp; |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |