Funciones miembro versus funciones no miembro para operadores matemáticos

12

Estoy escribiendo una biblioteca de álgebra lineal (cuento largo, es una tarea escolar) que involucra matrices, vectores, etc. En el proceso de creación de esta biblioteca, voy a crear funciones que realicen operaciones matemáticas en objetos. Por ejemplo, transponer matriz, invertir matriz, normalizar vector, etc.

Tenía curiosidad sobre cuál es la "mejor práctica" para este tipo de función ... Es decir, ¿debería hacer que la función sea una función miembro o no miembro? (Para mayor claridad / uso de la biblioteca sake)

Ejemplo:

//Member function way:
B = A.transpose();
C = A.inverse();

//Non-member function way:
B = linalg::transpose(A); //Non-member transpose function in linear algebra namespace
C = linalg::inverse(A);

¿Hay algún estándar con respecto a este tipo de operaciones? O, al menos, ¿hay una forma común en que la gente hace esto? Me estoy inclinando hacia la primera opción, pero me gustaría saber si esto se recomienda.

Apnorton
fuente

Respuestas:

7

Esto es solo una cuestión de estilo y gusto. He visto diferentes bibliotecas de álgebra lineal, ya sea

  • escrito en un estilo OOP usando funciones miembro

  • escrito en un estilo que no es OOP usando solo funciones libres

  • proporcionando una API con ambos

y todos ellos estaban trabajando. Al menos, su API debe ser consistente, así que elija su opción y asegúrese de no mezclar esos estilos arbitrariamente.

Doc Brown
fuente
8

Evite las cuotas de membresía: siempre que sea posible, prefiera hacer funciones de no miembros que no sean amigos.

Las funciones no miembro no miembro mejoran la encapsulación al minimizar las dependencias: el cuerpo de la función no puede depender de los miembros no públicos de la clase (ver Artículo 11). También separan las clases monolíticas para liberar la funcionalidad separable, lo que reduce aún más el acoplamiento (ver Artículo 33). Mejoran el carácter genérico, porque es difícil escribir plantillas que no sepan si una operación es miembro de un tipo dado [...]

Sutter de hierbas


fuente
1
Finalmente una buena respuesta: tarde, pero no demasiado tarde. ;-) Otra referencia: GotW # 84: Monolitos "Unstrung"
Deduplicator
1

Ambas funciones, miembros y no miembros, tienen ventajas reales además del mero gusto. Por ejemplo, la (s) matriz (s) subyacente (s) utilizada (s) para implementar una matrixclase probablemente será private, por lo tanto, deberá usarla a friendmenos que use funciones miembro. A este respecto, un diseño OO puede ser mejor.

Sin embargo, tenga en cuenta que, de vez en cuando, los científicos informáticos tienen que implementar fórmulas matemáticas complejas sin saber siempre lo que realmente hace. Cuando tengo que hacerlo, prefiero las funciones que no son miembros ya que el resultado "visual" estará más cerca de la fórmula matemática original (dado que la fórmula matemática generalmente usa un estilo funcional).

Al final, la respuesta es la misma que la del Doc Brown: es cuestión de gustos. En resumen, podría considerar escribir una biblioteca de estilo OO con funciones miembro (más fácil de escribir, no friend), luego escribir funciones que no sean miembros para hacer las mismas tareas que simplemente enviarán sus argumentos a las miembros. Le permite ser coherente y dejar que el usuario elija lo que cree que es mejor.

Morwenn
fuente
0

Si profundiza en su enunciado del problema, está claro que en algún momento utilizará estructuras de datos personalizadas que representan ciertas entidades matemáticas. Por ejemplo, usted podría representar una matriz mi medio de una matriz n-dimensional. Para elaborar su ejemplo,

// C way
typedef struct {
    int data[MAX_LEN][MAX_LEN];
} MATRIX;

MATRIX B = transpose(A);

// C++ way
class Matrix; // Forward Declaration
class Matrix {
    int data[MAX_LEN][MAX_LEN];
    public:
        Matrix transpose();
};

Matrix B = A.transpose();

(El ejemplo de C ++ está simplificado, puede usar plantillas y demás).

El punto a considerar es la facilidad de usar estructuras de datos personalizadas en ambos casos. C ++ (o cualquier objeto orientado) como lenguaje es más poderoso en sí mismo, y eso se extiende al consumidor de la biblioteca tanto como beneficia al implementador. ¡He usado bibliotecas C solo en el pasado y esas estructuras de datos personalizadas parecen llegar por todas partes en muy poco tiempo! Mientras que la interoperabilidad es más fácil de lograr con este último (¿usando constructores especiales, tal vez?)

Para terminar, si estás usando C ++, definitivamente se recomienda un enfoque orientado a objetos.

dotbugfix
fuente
55
Lo sentimos, hay muy pocos hechos sólidos en tu razonamiento. No hay diferencia en la facilidad de uso entre sus dos transposeejemplos. La razón principal por la que C ++ es más fácil es porque la semántica de copia y asignación realmente funciona. A = Bpuede compilarse en C pero probablemente hace algo incorrecto.
MSalters
+1 para la semántica de copia El punto que estaba tratando de transmitir es el uso de objetos (encapsulaciones sobre "representaciones") v / s usando un conjunto de estructuras y funciones relacionadas poco acopladas.
dotbugfix