Access Function in C++

As we discussed, classes typically make their data members private, and private members can not be directly accessed by the public.

Consider the following Date class:

#include <iostream>

class Date
{
private:
    int m_year{ 2020 };
    int m_month{ 10 };
    int m_day{ 14 };

public:
    void print() const
    {
        std::cout << m_year << '/' << m_month << '/' << m_day << '\n';
    }
};

int main()
{
    Date d{};  // create a Date object
    d.print(); // print the date

    return 0;
}

While this class provides a print() member function to print the entire date, this may not be sufficient for what the user wants to do. For example, what is the user of a Date object wanted to get the year, or to change the year to a different value. They would be unable to do so, as m_year is private (and thus can't be directly accessed by the public).

Access Functions

An access function is a trivial public member function whose job is to retrieve or change the value of a private member variable.

Access functions come in two flavors: getters and setters. Getters (also sometimes called accessors) are public member functions that return the value of a private member variable. Setters (also sometimes called mutators) are public member functions that set of a private member variable.

Getters are usually made const, so they can be called on both const and non-const objects. Setters should be non-const, so they can modify the data members.

Let's update our Date class to have a full set of getters and setters:

#include <iostream>

class Date
{
private:
    int m_year { 2020 };
    int m_month { 10 };
    int m_day { 14 };

public:
    void print()
    {
        std::cout << m_year << '/' << m_month << '/' << m_day << '\n';
    }

    int getYear() const { return m_year; }        // getter for year
    void setYear(int year) { m_year = year; }     // setter for year

    int getMonth() const  { return m_month; }     // getter for month
    void setMonth(int month) { m_month = month; } // setter for month

    int getDay() const { return m_day; }          // getter for day
    void setDay(int day) { m_day = day; }         // setter for day
};

int main()
{
    Date d{};
    d.setYear(2021);
    std::cout << "The year is: " << d.getYear() << '\n';

    return 0;
}

Access function naming

There is no common convention for naming access functions. However, there are few naming conventions that are more popular than others.

  • Prefixed with “get” and “set”:
int getDay() const { return m_day; }  // getter
void setDay(int day) { m_day = day; } // setter

The advantage of using “get” and “set” prefixes is that it makes it clear that these are  access functions.

  • No prefix:
int day() const { return m_day; }  // getter
void day(int day) { m_day = day; } // setter

The style is more concise, and uses the same name for both the getter and setter (relying on function overloading to differentiate the two). The C++ standard library uses this convention.

The downside of the no-prefix convention is that it is not particularly obvious that this is setting the value of the day member:

d.day(5); // does this look like it's setting the day member to 5?
  • “set” prefix only:
int day() const { return m_day; }     // getter
void setDay(int day) { m_day = day; } // setter

Getters should return by value or by const lvalue reference

Getters should provide “read-only” access to data. Therefore, the best practice is that they should return by either value (if making a copy of the member is inexpensive) or by const lvalue reference.