CLOSE
Updated on 17 Jun, 202512 mins read 26 views

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.