1

I'm trying to declare a vector containing user objects in the header file, but I'm unsure of how to use the setter and getter functions to push values objects back to the vector or call them again.

class userbase
{
    public:
        userbase();
        virtual ~userbase();

        //FUNCTION DECLARATIONS
        void record_User(user);

        void setUserVector(vector<user> const &newUser) {
          //userbase_V = newUser;
          userbase_V.push_back(newUser);
        }
        vector<user> const &getUservector() const {
          return userbase_V;
        }


    protected:

    private:
        vector <user> userbase_V;
 };
TrebledJ
  • 8,713
  • 7
  • 26
  • 48
McCoffee
  • 13
  • 3

1 Answers1

0

Getters/setters are quite often misunderstood. The aim of using such functions is encapsulation which means restricting access to your data or exposing certain functions.

The reason why we don't make private members public in the first place is because there are some operations that we don't want users of our class to perform.

Consider the following class:

class userbase
{
public:
    vector<user> users;
};

Let's say the goal of the userbase class is to manage a loyal, unwavering list of followers of an application. And since users is a public member, we can do whatever we want with it:

class company
{
public:
    void massacre()
    {
        m_userbase.users.clear();   // Aaaaahhh!!!
    }

private:
    userbase m_userbase;
};

What? Where did all our loyal, unwavering followers go? We can't just remove our users!

The company class has access to all of std::vector's functionality on m_userbase.users. But really, from userbase's point of view, we don't want the outside to access particular functions (in this case, clear() or erase()). We want to restrict what operations can be performed (modifiers) and what attributes can retrieved (accessors). That is, we want to encapsulate the users vector.

Making userbase a private member is the first step:

class userbase
{
private:
    vector<user> users;
};

Now let's add some naive "encapsulation" to see if it solves our problem. (This is where a lot of misunderstanding stems from.)

Here's our new class:

class userbase
{
public:
    void setUsers(vector<user> const& newUsers) {
        users = newUsers;
    }
    vector<user> const& getUsers() const {
        return users;
    }
private:
    vector<user> users;
}

Can the company still clear the users vector directly? Yes.

class company
{
public:
    void massacre()
    {
        auto users = m_userbase.getUsers();
        users.clear();
        m_userbase.setUsers(users);                 // Aaaaahhh!!!

        // or simply create a new vector with no data
        m_userbase.setUsers(std::vector<user>{});   // Aaaaahhh!!!
    }

private:
    userbase m_userbase;
};

So simply providing getters/setters doesn't solve the issue.

The common approach is to instead approach it the other way around. Instead of asking "What don't I want the outside to do?", ask "What do I want to allow the outside to do?". This way, you can figure what sort of functionality to expose. This is part of designing a good API.

Maybe our API wants to be able to: add a user, get a user's name, and count the number of users. Then we would design a class like this:

class userbase
{
public:
/// modifiers:

    // Add a user to the userbase.
    void addUser(User const& user);

/// accessors:

    // Returns the user's name given its index.
    string getUserName(size_t index) const;

    // Returns the number of users belonging to this userbase.
    size_t numberOfUsers() const;

private:
    vector<user> m_users;
};

The takeaway is: it's up to you to decide what "the outside" can or can't do with its members. You'll need to spend more time thinking and less time writing code, but this is normal.


Further reading:

Dharman
  • 30,962
  • 25
  • 85
  • 135
TrebledJ
  • 8,713
  • 7
  • 26
  • 48