Skip to main content

Section 16.5 Working with Members

Subsection 16.5.1 Accessing Member Variables in the Class

Look closely at the function getX(). What looks odd?
Listing 16.5.1.
class Point {
private:
    double m_x, m_y;

public:
    double getX() {
        return m_x;
    }
}
Notice that there is no declaration of m_x in this function! It is not declared as a parameter, nor is it declared as a local variable. So what is it?
It is the member variable of Point named m_x. Inside member functions, we always have access to the member variables of the object.
To call a member function, we always need to call it on a particular object:
p1.getX();
p2.getX();
Trying to use a member function without an object is a syntax error. There is no getX() function, there is only the getX() function that is a member of the Point class. (Point::getX() is the full name of this function - β€œthe getX that is a part of Point”.)
So when we say p1.getX() we are asking that object to execute the getX() code. When that code refers to return m_x;, it means β€œthe m_x value of p1”. Later on, if we say p2.getX(), the line return m_x;, it now means β€œthe m_x value of p2”.
Run this Codelens sample. Pay special attention each time it enters the getX function. You will see a stack frame for Point::getX(), and in that stack frame, you will see a variable called this that points at the object that is running the code. During the first call to Point::getX(), it will point to p1 since we called p1.getX() on line 23. Then, on line 26 when we call p2.getX(), this will be pointing at p2.
Listing 16.5.2.
A hand drawn memory diagram might look like this:
When getX is called on p1, this refers to p1
Figure 16.5.3. A memory diagram of p1 executing getX

Note 16.5.1.

We will learn more about exactly what this is in SectionΒ 18.9. For now, you can think of it as an alias for β€œthe object running the code”. When we say m_x in a member function, it is understood to mean this->m_x or β€œthe m_x variable of the object running this code”.

Checkpoint 16.5.1.

Examine this code. Then decide what best describes the meaning of m_red on line 6.
class Color {
private:
    int m_red, m_green, m_blue;
public:
    int getRed() {
        return m_red;
    }
};

int main() {
    Color c1;
    Color c2;
    c1.getRed();
}
  • The m_red value of whatever point is currently executing getRed()
  • The m_red value of c1.
  • Although we only currently use getRed on c1, it is possible that we could later call it on c2. So m_red is not guaranteed to be the value of c1.
  • The m_red value of c2.
  • The m_red value of the Color class.
  • The class itself does not have a m_red value. The class is just a blueprint for creating objects. The m_red variable is a member of each instance of the class.

Subsection 16.5.2 Setters and Mutators

If we want to provide the ability for outside code to modify a member variable, we can add a setter function. These are functions that take a value and use that to set a member variable. This version of the Point class adds a setter for m_x:
Listing 16.5.4.
When main calls p1.setX(5.0), it passes in the value 5. The Point::setX() function stores that value into the m_x instance variable of p1.
As with getters, setters provide a limited way for outside code to manipulate the object. Outside code can’t directly change m_x, it has to use the interface to ask a given point to please make the change to itself. This means that we have loose coupling and also that the class can β€œprotect itself” from unsafe or unwanted changes.
Say you are creating a Person class and you want to make sure that the age of a person never gets set to a negative value. You could design the class to prevent that from happening:
Listing 16.5.5.
When other code tries to set a negative age, the Person class ignores that request and prints an error message. (It would make even more sense in a real program to throw an exception there.)

Insight 16.5.2.

Remember the β€œtwo programmers” tip for understanding Object Oriented Programming.
The person programming Person is the expert who knows all the important ins and outs of the Person class. They know that a negative value is going to cause problems later. The person programming main does not realize that issue even exists. If they could set `p1.m_age = -5;` directly, they could end up causing the program to do something horrible later on.
By forcing others to use the public interface and then preventing unwanted modifications in that interface, the programmer of the Point class is able to limit the potential for such issues.
Setters are a special kind of mutator function. A mutator is any function that changes the state of an object. While a setter sets a member to a particular value, another kind of mutator might set more than one value or change a variable in a way that doesn’t allow outside code to set a particular value.
For instance, a person might have a void getOlder() function that looked like:
Listing 16.5.6.
class Person {
private:
    int m_age;
public:
    void getOlder() {
        m_age++;
    }
    ...
getOlder mutates (changes) the object. But it doesn’t allow other code to change the age to an arbitrary value.

Checkpoint 16.5.2.

In main we want to create a Circle, set the radius to 2.4 and output the radius. Then change the radius to 3.6 and output the new radius. We want to use the public interface of the Circle class and not depend on the private details of the class.
Put the correct blocks of code in the correct order.
You have attempted of activities on this page.