Функции-члены и не-функции для математических операторов

12

Я пишу библиотеку линейной алгебры (короче говоря, это школьное задание), которая включает в себя матрицы, векторы и т. Д. В процессе создания этой библиотеки я буду создавать функции, которые выполняют математические операции над объектами. Например, транспонировать матрицу, инвертировать матрицу, нормализовать вектор и т. Д.

Мне было любопытно, какова «лучшая практика» для такого рода функций ... То есть я должен сделать функцию функцией-членом или не-членом? (Для наглядности / пользуйтесь библиотекой ради)

Пример:

//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);

Есть ли какой-то стандарт в отношении таких операций? Или, по крайней мере, есть ли общий способ, которым люди делают это? Я склоняюсь к первому варианту, но я хотел бы знать, рекомендуется ли это.

apnorton
источник

Ответы:

7

Это просто вопрос стиля и вкуса. Я видел разные библиотеки линейной алгебры, либо

  • написано в стиле ООП с использованием функций-членов

  • написано не в стиле ООП с использованием только бесплатных функций

  • предоставление API с обоими

и все они работали. По крайней мере, ваш API должен быть согласованным, поэтому выберите свой выбор и убедитесь, что вы не смешиваете эти стили произвольно.

Док Браун
источник
8

Избегайте членских взносов: по возможности, предпочитайте, чтобы функции не были членами группы.

Функции, не являющиеся членами, не являющимися членами, улучшают инкапсуляцию за счет минимизации зависимостей: тело функции не может зависеть от непубличных членов класса (см. Пункт 11). Они также разбивают монолитные классы, освобождая разделяемую функциональность, дополнительно уменьшая связь (см. Пункт 33). Они улучшают универсальность, потому что трудно писать шаблоны, которые не знают, является ли операция членом данного типа [...]

Херб Саттер


источник
1
Наконец хороший ответ: поздно, но не слишком поздно. ;-) Другая ссылка: ПОЛУЧИЛ 84: Монолиты "Unstrung"
дедупликатор
1

Функции-члены и не-члены имеют реальные преимущества помимо простого вкуса. Например, базовый массив (ы), используемый для реализации matrixкласса, вероятно, будет private, поэтому вам придется использовать, friendесли вы не используете функции-члены. В этом отношении ОО дизайн может быть лучше.

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

В конце концов, ответ такой же, как у Дока Брауна: это вопрос вкуса. Короче говоря, вы могли бы написать библиотеку в стиле ОО с функциями-членами (проще писать, нет friend), а затем написать функции, не являющиеся членами, для выполнения тех же задач, которые просто передадут свои аргументы членам. Это позволяет вам быть последовательным и позволить пользователю выбирать то, что он считает лучшим.

Morwenn
источник
0

Если вы углубитесь в формулировку проблемы, станет ясно, что в какой-то момент вы будете использовать пользовательские структуры данных, которые представляют определенные математические объекты. Например, вы можете представить матрицу моих средств из n-мерного массива. Чтобы уточнить на вашем примере,

// 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();

(Пример C ++ упрощен, вы можете использовать шаблоны и тому подобное.)

Необходимо учитывать простоту использования пользовательских структур данных в обоих случаях. C ++ (или любой объектно-ориентированный) как язык сам по себе является более мощным, и это распространяется на потребителя библиотеки настолько, насколько это приносит пользу разработчику. В прошлом я использовал библиотеки только на C, и эти пользовательские структуры данных, кажется, быстро распространяются! Принимая во внимание, что с последним легче взаимодействовать (возможно, с использованием специальных конструкторов?)

В заключение, если вы используете C ++, тогда определенно рекомендуется объектно-ориентированный подход.

dotbugfix
источник
5
Извините, в ваших рассуждениях очень мало убедительных фактов. Там нет разницы в простоте использования между вашими двумя transposeпримерами. Основная причина C ++, т.е. проще, заключается в том, что семантика копирования и присваивания фактически работает. A = Bможет компилироваться в C, но, вероятно, делает неправильные вещи.
MSalters
+1 для семантики копирования Пункт, который я пытался донести, - это использование объектов (инкапсуляция над «представлениями») v / s с использованием слабосвязанного набора структур и связанных функций.
dotbugfix