2012-07-04 12 views
10

Tengo una pequeña pregunta teórica, sin embargo, es un problema que a veces enfrento al diseñar clases y veo que se hace de manera diferente cuando se lee código ajeno. ¿Cuál de los siguientes sería mejor y por qué:Diseño de clase: matrices frente a variables múltiples

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

ejemplo 2:

class Color 
{ 
public: 
    // as above 

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

¿Hay una regla general, uno debe seguir en casos como este o es sólo hasta un programador y lo que parece tener más sentido?

+0

BTW ¿tiene alguna razón práctica de por qué mantener los campos privados aquí? – Kos

+0

@Kos, dado el ejemplo, podría ver fácilmente el uso de accesos y mutadores para restringir la entrada, aunque cada campo probablemente debería ser 'byte' en lugar de' float'. Además, se pueden usar valores de cadena como '# ABCDEF' y' # ABC'. – zzzzBov

Respuesta

4

Depende, ¿tiene la intención de iterar en toda la matriz?

En ese caso, creo que la solución 1 es más apropiada. Es muy útil tener una matriz como esa cuando tiene funciones que operan en un bucle en los datos

p.

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

vs

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

Por supuesto esto es trivial, y creo que lo que realmente es una cuestión de preferencia. En algunas raras ocasiones es posible que tenga API que toman un puntero a los datos, sin embargo, y mientras que puede hacer

awesomeAPI((float*)&r); 

me gusta mucho preferiría hacer

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

porque la matriz garantizará su contigüidad, mientras que puede estropear la contigüidad al agregar por error otra variable miembro que no está relacionada después de float r.


Rendimiento sabio no habría diferencia.

+0

El argumento de iteración es en mi humilde opinión la clave, pero creo que en el caso de los colores, argumenta de otra manera. No puedo pensar en un caso en el que tenga sentido aumentar cada color por el mismo valor. –

+0

No podemos suponer qué va a hacer el usuario con el color; por todo lo que sabemos, podrían usar la clase Color para almacenar las normales de los vértices codificados esféricamente. –

1

¿Hay una regla general que uno debe seguir en casos como este o solo le corresponde a un programador y lo que parece tener más sentido?

Definitivamente depende del programador y de lo que sea que tenga más sentido.

En su caso, la segunda opción parece más apropiada. Después de todo, lógicamente pensando, su miembro no es una matriz de valores, sino valores para r, g y b.

+0

¿Con cuál de las dos opciones está "definitivamente" de acuerdo? –

+0

@larsmans jaja - hasta el programador y lo que tiene más sentido. –

0

Ventajas del uso de una matriz:

  • mantenimiento: puede utilizar los valores de la matriz de bucle
  • de mantenimiento: Cuando un valor añadido debe ser (como el amarillo?) Que no tiene para cambiar una gran cantidad de código

Desventaja:

  • Legibilidad: Los 'valores' tienen nombres más claras (es decir, R, G, B en este caso).

En su caso, probablemente las variables r, g, b son las mejores, ya que es poco probable que se agregue un color y un ciclo de 3 elementos probablemente tenga una importancia menor que la legibilidad.

3

Yo diría que el segundo es el mejor.

En primer lugar, los datos que contienen sus variables no se supone (físicamente) en una matriz. Si tuviera, por ejemplo, una clase con 3 alumnos, ni más ni menos, los colocaría en una matriz, porque son una matriz de alumnos, pero aquí solo son colores.

En segundo lugar, una persona que lee su código también puede comprender en el segundo caso lo que contienen sus variables (r es rojo, etc.). No es el caso con una matriz.

En tercer lugar, tendrá menos errores, no tendrá que recordar "oh, en mi matriz, rojo es 0, g es 1, b es 2", y no reemplazará por error

return color_values[0] 

por

return color_values[1] 

en el código.

+0

Eso es cierto, pero al final del día depende de qué (s) usará los colores. Si ella va a convertir de RGB a HSL, que es básicamente una operación vectorial, la matriz podría ser más conveniente. Además, existe la posibilidad de indexar la matriz con una enumeración, como 'color_values ​​[red]' – deStrangis

+0

, sí, pensé en la enumeración, pero es un poco exagerado para una clase tan fácil: D – Tuxer

+0

+1. El significado está totalmente oscurecido por la referencia genérica de matrices. Además, una matriz transmite el sentido equivocado de los datos. r, g, b (mal nombrado por supuesto) son cosas diferentes. No son intercambiables en el procesamiento iterativo; no hay forma de establecer o obtener valores correctamente sin conocer el contexto. Por lo tanto, no podemos usar el beneficio de la estructura de matriz. – radarbob

2

Creo que tienes razón: "Solo para un programador y lo que parece tener más sentido". Si este fuera mi programa, elegiría una forma u otra sin preocuparme demasiado por ella, luego escribiré otras partes del programa y luego volveré a tratar el tema más adelante.

Uno de los beneficios del diseño orientado a clases es que hace que los detalles de implementación interna de este tipo sean privados,, lo que hace que sea conveniente modificarlos más adelante.

Creo que su pregunta sí importa, pero dudo que se pueda responder bien hasta que se haya escrito más código. En abstracto, solo hay tres elementos, y los tres tienen nombres: rojo, verde y azul, así que creo que podrías ir de cualquier manera con esto. Si se ve obligado a elegir, elijo el ejemplo 2.

10

Ambos!

Utilice esta:

class Color { 

    // ... 

private: 

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

}; 

Entonces c[0] será equivalente a r, etcétera.

+1

¡La mejor respuesta real, obtenga lo mejor de ambos mundos! –

+1

+1 por astucia. No había pensado en esto. (Respecto al estándar de lenguaje legalista, no estoy 100 por ciento seguro de que esto siempre funcione, pero incluso si no es legalista, aún así prácticamente funcionará. Es difícil imaginar un compilador que pueda romper tu respuesta). – thb

+0

@thb It está bien definido si 'sizeof (the_anonymous_struct_with_the_three_floats) == 3 * sizeof (float)', que no es una suposición demente. Supongo que si eres paranoico, puedes 'static_assert'. –

0

A veces un programador utilizará una matriz (o estructura de datos) para guardar los datos más rápidamente en el disco (o memoria) utilizando 1 operación de escritura. Esto es especialmente útil si está leyendo y escribiendo una gran cantidad de datos.

Cuestiones relacionadas