私は、行列、ベクトルなどを含む線形代数ライブラリ(長い話では、学校の課題です)を書いています。このライブラリを作成する過程で、オブジェクトに対して数学演算を実行する関数を作成します。たとえば、行列の転置、行列の反転、ベクトルの正規化など。
この種の関数の「ベストプラクティス」とは何なのか知りたくて...つまり、関数をメンバー関数にするか、非メンバーにするか? (明確にするために/ライブラリを使用するため)
例:
//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);
この種の操作に関する基準はありますか?または、少なくとも、これを行う一般的な方法はありますか?私は最初のオプションに傾いていますが、これが推奨されるかどうか知りたいのですが。
これはスタイルと味の問題です。さまざまな線形代数ライブラリを見たことがあります。
メンバー関数を使用してOOPスタイルで記述
フリー関数のみを使用して非OOPスタイルで記述
両方でAPIを提供する
そして彼ら全員が働いていました。少なくとも、APIは一貫している必要があります。そのため、選択肢を選び、それらのスタイルを任意に混在させないようにしてください。
会費を避ける:可能であれば、機能を非友だち以外のメンバーにすることをお勧めします。
非メンバーの非フレンド関数は、依存関係を最小限に抑えることでカプセル化を改善します。関数の本体は、クラスの非パブリックメンバーに依存することができなくなります(アイテム11を参照)。また、モノリシッククラスを分解して分離可能な機能を解放し、カップリングをさらに削減します(項目33を参照)。操作が特定のタイプのメンバーであるかどうかを知らないテンプレートを書くのは難しいので、それらは一般性を向上させます[...]
ハーブサッター
メンバー関数と非メンバー関数の両方に、単なる味だけでなく実際の利点があります。たとえば、matrix
クラスの実装に使用される基になる配列はおそらくprivate
になるため、メンバー関数を使用しない限り、friend
を使用する必要があります。この点で、OOデザインがより良いかもしれません。
ただし、コンピュータサイエンティストは、実際に何をしているのかを常に知らなくても、複雑な数式を実装しなければならない場合があることを覚えておいてください。私がそうしなければならないときは、「視覚的な」結果が元の数式に近づくため、非メンバー関数を好みます(数式は一般に関数スタイルを使用するため)。
結局のところ、答えはDoc Brownの答えと同じです。それは好みの問題です。要するに、メンバー関数を使ってオブジェクト指向スタイルのライブラリーを書くこと(書くのが簡単、friend
なし)を考え、その後、メンバー以外の関数を書いて、引数をメンバーの関数に転送するだけの同じタスクを実行することを検討できます。 。これにより、一貫性を保つことができ、ユーザーが最良と考えるものをユーザーが選択できるようになります。
問題の説明をより深く掘り下げる場合、特定の数学的エンティティを表すカスタムデータ構造をいつの時点で使用するかは明らかです。たとえば、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++を使用している場合は、オブジェクト指向のアプローチをお勧めします。