Векторы Классы Частные / Публичные - PullRequest
2 голосов
/ 30 августа 2011

В C ++ всегда лучше хранить данные класса в качестве закрытых членов.
Если у класса есть вектор в качестве члена, лучше поместить его в качестве закрытого или открытого члена?

Если у меня естьвектор как закрытый член Я не могу легко получить доступ к функции-члену вектора.Поэтому я должен спроектировать класс с методом для каждой функции, которая мне нужна для доступа к векторным методам?

Пример:

class MyClass{
private:
     std::vector<int> _myints;
public:
     get_SizeMyints(){return _myints.size();}
     add_IntToMyints(int x){_myints.push_back(x));
};

или лучше оставить вектор открытым и вызвать MyClass._myints.push_back (x)?

--------------------- edit --------------

и просто для ясности, для чего нужен этот вопрос:

snake.h:

enum directions{UP, DOWN, RIGHT, LEFT, IN, OUT, FW, RW };


class Snake
{
private:
    enum directions head_dir;
    int cubes_taken;
    float score;
    struct_color snake_color;
    V4 head_pos;


public:

    std::vector<Polygon4> p_list; //the public vector which should be private...

    Snake();
    V4 get_head_pos();
    Polygon4 create_cube(V4 point);
    void initialize_snake();
    void move(directions);

    void set_head_dir(directions dir);
    directions get_head_dir();
    void sum_cubes_taken(int x);
    int get_cube_taken();

    void sum_score(float x);
    float get_score();

    void set_snake_color();



};

так что теперь я знаю, как изменить код.

Кстати ... вопрос, если мне нужно скопировать вектор в другой класс, как это: GlBox.p_list = Snake.p_list (работает, если являются частными), что будет эффективным методом, если они являются частными?
Запуск цикла for для копирования элементов и возврат их обратно в GLBox.p_list кажется мне неэффективным (но может показаться, что это просто впечатление): (

Ответы [ 7 ]

4 голосов
/ 30 августа 2011

Если не имеет значения, если кто-то придет и освободит вектор или переставит все его элементы, то сделайте его публичным.Если это имеет значение, тогда да, вы должны сделать его защищенным / закрытым, и сделать общедоступные оболочки, как у вас.[Править] Поскольку вы говорите «это змея», это значит, что было бы плохо, если бы кто-то пришел и убрал или заменил биты.Ergo, вы должны сделать его защищенным или частным.[/ Edit]

Вы можете упростить многие из них:

MyClass {
private:
     std::vector<int> _myints;
public:
     const std::vector<int>& get_ints() const {return _myints;}
     add_IntToMyints(int x){_myints.push_back(x));
};

Эта функция get_ints() позволит кому-то смотреть на вектор все, что он хочет, но не позволитизменить что-нибудь.Однако, лучшая практика - полностью инкапсулировать вектор.Это позволит вам заменить вектор декой или списком или чем-то еще позже.Вы можете получить размер с std::distance(myobj.ints_begin(), myobj.ints_end());

MyClass {
private:
     std::vector<int> _myints;
public:
     typedef std::vector<int>::const_iterator const_iterator;
     const_iterator ints_begin() const {return _myints.begin();}
     const_iterator ints_end() const {return _myints.end();}
     add_IntToMyints(int x){_myints.push_back(x));
};
2 голосов
/ 30 августа 2011

Ваш вопрос не очень конкретен, поэтому вот ответ в том же духе:

Как правило, ваши классы должны быть разработаны, чтобы выразить определенную концепцию и функциональность.Они не должны просто сдавать другой член класса.Если вы обнаружите, что реплицируете все функции интерфейса объекта-члена, что-то не так.

Может быть, иногда вам просто нужен набор других вещей.В этом случае рассмотрим простой старый агрегат или даже кортеж.Но если вы разрабатываете правильный класс, сделайте интерфейс значимым для поставленной задачи и скройте реализацию.Итак, главный вопрос здесь: зачем вам выставлять сам вектор?Какова его роль в классе?Что означает его пустота с точки зрения семантики вашего класса?

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

(Еще одна идея: если, например, у вас есть какие-то потребности, основанные на диапазоне, рассмотрите возможность использования функции-члена шаблона, принимающей пару итераторов. Таким образом, вы используете возможности универсальных алгоритмов, не завися от выбора контейнера.)1009 *

2 голосов
/ 30 августа 2011

Для хорошей инкапсуляции вы должны держать свой вектор закрытым.

0 голосов
/ 30 августа 2011

Следует понимать, что создание приватного std::vector - это только половина истории, когда дело доходит до хорошей инкапсуляции.Например, если у вас есть:

class MyClass {
    public:
        // Constructors, other member functions, etc.

        int getIntAt(int index) const;

    private:
        std::vector<int> myInts_;
};

... тогда, возможно, это не лучше, чем просто сделать myInts_ публичным.В любом случае клиенты будут писать код, используя MyClass, что зависит от того факта, что базовое представление требует использования std::vector.Это означает, что в будущем, если вы решите, что более эффективная реализация будет использовать std::list вместо:

class MyClass {
    public:
        // Constructors, other member functions, etc.

        int getIntAt(int index) const; // whoops!

    private:
        std::list<int> myInts_;
};

... теперь у вас есть проблема.Поскольку вы не можете получить доступ к std::list по индексу, вам придется либо избавиться от getIntAt, либо реализовать getIntAt с помощью цикла.Ни один из вариантов не хорош;в первом случае у вас теперь есть клиенты с кодом, который не компилируется.Во втором случае теперь у вас есть клиенты с кодом, который просто без вывода сообщений стал менее эффективным.

Это опасность раскрытия любых открытых функций-членов, которые являются специфическими для вашего выбора реализации.При проектировании интерфейса вашего класса важно помнить о гибкости и будущем обслуживании.Есть несколько способов сделать это с вашим конкретным примером;см. ответ Mooing Duck об одном таком интерфейсе, который предоставляет итераторы.

Или, если вы хотите максимизировать удобочитаемость кода, вы можете разработать интерфейс на основе логического представления MyClass;в вашем случае змея:

class MyClass {
    public:
        // Constructors, etc.

        void addToHead(int value);
        void addToTail(int value);
        void removeFromHead();
        void removeFromTail();

    private:
        // implementation details which the client shouldn't care about
};

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

0 голосов
/ 30 августа 2011

Теоретически в объектно-ориентированном программировании любые атрибуты должны быть закрытыми и получать к ним доступ через открытые методы, такие как Get () и Set (). Я думаю, что ваш вопрос не завершен, но из того, что вы пытаетесь достичь, я понимаю, что вам нужно наследовать от std :: vector и расширять его функциональные возможности, чтобы удовлетворить ваши потребности в быстром доступе и не возиться с инкапсуляцией. (Подумайте сначала о «Наследовании» из любой книги C ++ или другого языка OO)

Сказав это, ваш код может выглядеть следующим образом:

class MyClass : public std::vector<int>
{
     //whatever else you need goes here
}

int main(void)
{
     MyClass var;
     var.push_back(3);
     int size = var.size(); // size will be 1
}

Надеюсь, что это ответ на ваш вопрос

0 голосов
/ 30 августа 2011

Это зависит от цели вашего класса. Если вы просто пытаетесь обернуть вектор и хотите использовать его как вектор, вы могли бы сделать аргумент в пользу того, чтобы сделать этот вектор общедоступным.

Вообще говоря, я бы предложил сделать его приватным и предоставить соответствующий интерфейс для управления контейнером. Кроме того, это позволяет вам изменить контейнер под капотом, если другой контейнер будет более подходящим (если вы не привязываете свой открытый интерфейс к типу контейнера).

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

0 голосов
/ 30 августа 2011

Обычно, хорошая практика кодирования - сохранять ваши данные частными или защищенными и предоставлять любые общедоступные методы, необходимые для доступа к ним. Не все методы (в данном случае) вектора, только то, что будет полезно для вашего приложения.

...