2012-07-04 4 views
10

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

пример 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; 
} 

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

+0

Кстати, у вас есть практическая причина для того, чтобы держать здесь поля частными? – Kos

+0

@ Kos, приведенный в примере, я мог легко увидеть использование аксессуаров и мутаторов для ограничения ввода, хотя каждое поле должно быть, скорее, 'byte', а не' float'. Кроме того, могут использоваться строковые значения, такие как '# ABCDEF' и' # ABC'. – zzzzBov

ответ

4

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

В этом случае, думаю, решение 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.


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

+0

Итерационный аргумент - это ИМХО ключ, но я думаю, что в случае цветов он утверждает другой путь. Я не могу придумать случай, когда было бы целесообразно увеличить каждый цвет на одну и ту же величину. –

+0

Мы не можем делать предположения о том, что пользователь собирается делать с цветом; для всех, кого мы знаем, они могли бы использовать класс Color для хранения сферически закодированных нормалей вершин. –

1

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

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

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

+0

С каким из двух вариантов вы «определенно» согласны? –

+0

@larsmans haha ​​- до программиста и в чем смысл. –

0

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

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

Неудобство:

  • Читаемость: В 'значения' имеют более четкие имена (а именно R, G, B, в данном случае).

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

3

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

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

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

В-третьих, вы будете иметь меньше ошибок, вы не должны помнить «о, в моем массиве, красный 0, г = 1, Ь 2», и вы не заменит по ошибке

return color_values[0] 

по

return color_values[1] 

в вашем коде.

+0

Это правда, но в конце дня это зависит от того, для чего он будет использовать цвета. Если она собирается конвертировать из RGB в HSL, что в основном является векторной операцией, массив может быть более удобным. Кроме того, есть возможность индексировать массив с перечислением, например 'color_values ​​[red]' – deStrangis

+0

Да, я думал о перечислении, но это немного переборщик для такого легкого класса: D – Tuxer

+0

+1. Значение полностью скрывается от общего массива. Кроме того, массив передает неверный смысл данных. r, g, b (плохо названные, конечно) - разные вещи. Они не взаимозаменяемы при итеративной обработке; нет способа правильно установить или получить значения, не зная контекста. Поэтому мы не можем использовать преимущества структуры массива. – radarbob

2

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

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

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

10

Оба!

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

class Color { 

    // ... 

private: 

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

}; 

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

+1

Лучший фактический ответ, получите лучшее из обоих миров! –

+1

+1 для умения. Я не думал об этом. (Что касается языкового стандарта легалистически, я не уверен на 100%, что это всегда должно работать, но даже если это не законно, все равно практически это сработает. Трудно представить компилятор, который, вероятно, нарушит ваш ответ.) – thb

+0

@thb It корректно определяется, если 'sizeof (the_anonymous_struct_with_the_three_floats) == 3 * sizeof (float)', что не является безумным предположением. Я предполагаю, что если вы параноик, вы можете «static_assert» его. –

0

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

 Смежные вопросы

  • Нет связанных вопросов^_^