Частный вектор в заголовочном файле: как получить и установить значения

Я пытаюсь объявить вектор, содержащий пользовательские объекты, в заголовочном файле, но я не уверен, как использовать функции установки и получения для возврата объектов значений обратно в вектор или их повторного вызова.

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;
 };

Почему vector<user*>, а не vector<user>?

Paul Sanders 15.12.2020 10:14

На самом деле нет причин, я просто тестировал некоторые вещи. Я должен был изменить его обратно

McCoffee 15.12.2020 10:18
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
136
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Геттеры/сеттеры довольно часто понимают неправильно. Целью использования таких функций является инкапсуляция, что означает ограничение доступа к вашим данным или раскрытие определенных функций.

Причина, по которой мы не делаем закрытые члены общедоступными, в первую очередь заключается в том, что есть некоторые операции, которые мы не хотим, чтобы пользователи нашего класса выполняли.

Рассмотрим следующий класс:

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;
};

Вывод таков: вам решать, что «внешние» могут или не могут делать со своими членами. Вам придется тратить больше времени на размышления и меньше времени на написание кода, но это нормально.


Дальнейшее чтение:

Другие вопросы по теме