Дизайн классов: массивы против нескольких переменных

У меня немного теоретический вопрос, однако это проблема, с которой я иногда сталкиваюсь при разработке классов, и я вижу, что это делается по-другому, когда читаешь другие коды. Что из следующего было бы лучше и почему:

пример 1:

class Color
{
public:
  Color(float, float, float);
  ~Color();

  friend bool operator==(Color& lhs, Color& rhs);
  void multiply(Color);
  // ...
  float get_r();
  float get_g();
  float get_b();

private:
  float color_values[3];
}

Пример 2:

class Color
{
public:
  // as above

private:
  float r;
  float g;
  float b;
}

Есть ли общее правило, которое следует придерживаться в таких случаях, или это просто до программиста и что, по-видимому, имеет больше смысла?

Ответ 1

Это зависит от того, собираетесь ли вы выполнять итерацию по всему массиву?

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

например.

void BumpColors(float idx)
{
    for (int i = 0; i < 3; ++i)
        color_values[i] += idx;
}

против

void BumpColors(float idx)
{
    color_values[0] += idx;
    color_values[1] += idx;
    color_values[2] += idx;
}

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

awesomeAPI((float*)&r);

Я бы предпочел сделать

awesomeAPI((float*)&color_values[0]);

потому что массив гарантирует его смежность, тогда как вы можете испортить смежность, добавив по ошибке другую переменную-член, которая не связана после float r.


Производительность мудрых не будет никакой разницы.

Ответ 2

И

Используйте это:

class Color {

    // ...

private:

    union {
       struct {
           float r, g, b;
       };
       float c[3];
    };

};

Тогда c[0] будет эквивалентно r и т.д.

Ответ 3

Я бы сказал, что второй лучший.

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

Во-вторых, кто-то, кто читает ваш код, также может во втором случае быстро понять, что содержат ваши переменные (r - красный и т.д.). Это не относится к массиву.

В-третьих, у вас будет меньше ошибок, вам не нужно будет помнить "о, в моем массиве красный - 0, g - 1, b - 2", и вы не будете ошибочно заменяться

return color_values[0]

по

return color_values[1]

в вашем коде.

Ответ 4

Я думаю, что вы правы: "Это просто программист и, как представляется, имеет больше смысла". Если бы это была моя программа, я бы выбрал одну или другую форму, не беспокоясь об этом слишком много, а затем напишу некоторые другие части программы, а потом снова перейдем к вопросу.

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

Я думаю, что ваш вопрос имеет значение, только я сомневаюсь, что он может ответить на него хорошо, пока не будет написано больше кода. В реферате есть только три элемента, а три имеют имена - красный, зеленый и синий - поэтому я думаю, что вы могли бы пойти в любом случае с этим. Если принудительно выбрать, я выбираю пример 2.

Ответ 5

Есть ли общее правило, которое следует придерживаться в таких случаях, или это просто до программиста и что, по-видимому, имеет больше смысла?

Это определенно зависит от программиста и имеет смысл.

В вашем случае второй вариант кажется более подходящим. В конце концов, логически думая, ваш член не является массивом значений, а значениями для r, g и b.

Ответ 6

Преимущества использования массива:

  • Поддержание работоспособности: вы можете использовать значения в массиве для цикла
  • Поддержание работоспособности: когда нужно добавить значение (например, желтый?), чем вам не нужно менять много кода.

Неудобство:

  • Читаемость: "значения" имеют более четкие имена (а именно, r, g, b в этом случае).

В вашем случае, вероятно, лучше всего использовать переменные r, g, b, так как маловероятно, что цвет добавляется, а цикл над 3 элементами, вероятно, имеет меньшее значение, чем читаемость.

Ответ 7

Иногда программист будет использовать массив (или структуру данных) чтобы быстрее сохранить данные на диск (или память), используя 1 операцию записи. Это особенно полезно, если вы читаете и записываете много данных.