Я пытаюсь объявить вектор, содержащий пользовательские объекты, в заголовочном файле, но я не уверен, как использовать функции установки и получения для возврата объектов значений обратно в вектор или их повторного вызова.
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;
};
На самом деле нет причин, я просто тестировал некоторые вещи. Я должен был изменить его обратно
Геттеры/сеттеры довольно часто понимают неправильно. Целью использования таких функций является инкапсуляция, что означает ограничение доступа к вашим данным или раскрытие определенных функций.
Причина, по которой мы не делаем закрытые члены общедоступными, в первую очередь заключается в том, что есть некоторые операции, которые мы не хотим, чтобы пользователи нашего класса выполняли.
Рассмотрим следующий класс:
class userbase
{
public:
vector<user> users;
};
Допустим, цель класса userbase
— управлять лояльным, непоколебимым списком подписчиков приложения. А поскольку users
является публичным членом, мы можем делать с ним все, что захотим:
class company
{
public:
void massacre()
{
m_userbase.users.clear(); // Aaaaahhh!!!
}
private:
userbase m_userbase;
};
Что? Куда делись все наши верные, непоколебимые последователи? Мы не можем просто удалить наших пользователей!
Класс company
имеет доступ ко всем функциям std::vector
на m_userbase.users
. Но на самом деле, с точки зрения userbase
, мы не хотим, чтобы снаружи был доступ к определенным функциям (в данном случае clear()
или erase()
). Мы хотим ограничить, какие операции можно выполнять (модификаторы) и какие атрибуты можно извлекать (аксессоры). То есть мы хотим инкапсулировать вектор users
.
Сделать userbase
приватным участником — это первый шаг:
class userbase
{
private:
vector<user> users;
};
Теперь давайте добавим наивную «инкапсуляцию», чтобы посмотреть, решит ли она нашу проблему. (Отсюда много недоразумений.)
Вот наш новый класс:
class userbase
{
public:
void setUsers(vector<user> const& newUsers) {
users = newUsers;
}
vector<user> const& getUsers() const {
return users;
}
private:
vector<user> users;
}
Может ли компания по-прежнему очищать вектор users
напрямую? Да.
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;
};
Таким образом, простое предоставление геттеров/сеттеров не решает проблему.
Обычный подход состоит в том, чтобы вместо этого подойти к этому с другой стороны. Вместо того, чтобы спрашивать: «Чего я не хочу, чтобы делало внешнее?», спросите: «Что я хочу позволить делать внешнему?». Таким образом, вы можете понять, какую функциональность выставлять. Это часть разработки хорошего API.
Возможно, наш API хочет иметь возможность: добавлять пользователя, получать имя пользователя и подсчитывать количество пользователей. Затем мы разработали бы такой класс:
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;
};
Вывод таков: вам решать, что «внешние» могут или не могут делать со своими членами. Вам придется тратить больше времени на размышления и меньше времени на написание кода, но это нормально.
Дальнейшее чтение:
Почему
vector<user*>
, а неvector<user>
?