Free Hosting

Access functions and encapsulation


Access functions
An access function is a short public function whose job is to return the value of a private member variable. For example, in the above mentioned String class, you might see something like this:
1
2
3
4
5
6
7
8
9
class String
{
private:
    char *m_chString; // a dynamically allocated string
    int m_nLength; // the length of m_chString
 
public:
    int GetLength() { return m_nLength; }
};
GetLength() is an access function that simply returns the value of m_nLength.
Access functions typically come in two flavors: getters and setters. Getters are functions that simply return the value of a private member variable. Setters are functions that simply set the value of a private member variable.
Here’s an example class that has some getters and setters:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Date
{
private:
    int m_nMonth;
    int m_nDay;
    int m_nYear;
 
public:
    // Getters
    int GetMonth() { return m_nMonth; }
    int GetDay() { return m_nDay; }
    int GetYear() { return m_nYear; }
 
    // Setters
    void SetMonth(int nMonth) { m_nMonth = nMonth; }
    void SetDay(int nDay) { m_nDay = nDay; }
    void SetYear(int nYear) { m_nYear = nYear; }
};
Why bother to make a member variable private if we’re going to provide public access functions to it? The answer is: “encapsulation”.
Encapsulation
In real life, it is common to use something without knowing how it actually works. For example, your TV remote provides buttons that allow you to do things like turn your TV on and off and adjust the volume. However, the details of how the remote is actually implemented is hidden away. This is useful because it allows you to use the remote without having to worry about the details of why it works or how it was implemented. If gnomes broke into your house in the middle of the night and replaced the internals of your TV remote with a new (but compatible) technology, you’d probably never even notice.
Encapsulation is the idea of hiding the details of how something is implemented and instead exposing an interface to the user. This allows the user to use the item without having to worry about how it is implemented.
In C++, access specifiers allow us to implement encapsulation within our classes. This is typically done by making ALL member variables of a class private, and providing public functions (often access functions) that allow the user to work with the class. Although this may seem more burdensome than providing public access directly, doing so actually provides several very useful benefits that help encourage class reusability and maintainability.
Perhaps most importantly, sometimes it turns out that the initial implementation of a class is too slow or uses too much memory, and a more complex solution is needed. Encapsulating the implementation means that the implementation of a class can be completely changed, and so long as the interface remains the same, the users of the class do not have to worry about the changes at all!
Consider this simple example:
1
2
3
4
5
6
7
8
9
10
11
12
class Change
{
public:
    int m_nValue;
};
 
int main()
{
    Change cChange;
    cChange.m_nValue = 5;
    std::cout << cChange.m_nValue << std::endl;
};
While this program works fine, what would happen if we decided to rename m_nValue? We’d also break our program! Encapsulation gives us the ability to change our classes without breaking all the code that uses them.
Here is the encapsulated version of this class that uses access functions to access m_nValue:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Change
{
private:
    int m_nValue;
 
public:
    void SetValue(int nValue) { m_nValue = nValue; }
    int GetValue() { return m_nValue; }
};
 
int main()
{
    Change cChange;
    cChange.SetValue(5);
    std::cout << cChange.GetValue() << std::endl;
}
Now when we decide to rename m_nValue, we only need to change SetValue and GetValue() to reflect the change. Our program does not need to be changed at all!
Second, hiding the details about how a class is implemented means a programmer can use the class without knowing how it was implemented. This lowers the time needed to learn how to use a class, and makes the class much easier to work with.
Third, encapsulation helps prevent accidental changes and misuse. Because the member variables can not be accessed directly, this helps prevent inadvertent changing of values. Furthermore, it is often the case that when a value is modified, other values also need to be updated. For example, in a typical String class, when the string is modified, the length also needs to be updated. If the user has direct access to the string, he/she may forget to update the length when the string is changed. However, an interface function that allows the user to change the string can automatically update the length whenever the string is changed, meaning the user doesn’t even have to worry about it!
And finally, encapsulation helps you debug the program when something goes wrong. Often when a program does not work correctly, it is because one of our member variables has an incorrect value. If everyone is able to access the variable directly, tracking down which piece of code modified the variable can be difficult. However, if everybody has to call the same function to modify a variable, you can simply breakpoint that function and watch as each caller changes the value until you see where it goes wrong.
As you can see, encapsulation provides a lot of benefits for just a little bit of effort. In particular, the ability to change the implementation details of the class without affecting any of the programs that use the class is paramount to code maintainability

0 comments:

Blogger Template by Clairvo