Piszę bibliotekę algebry liniowej (krótko mówiąc, jest to zadanie szkolne), która obejmuje macierze, wektory itp. W trakcie tworzenia tej biblioteki będę tworzyć funkcje, które wykonują operacje matematyczne na obiektach. Na przykład transponuj macierz, odwróć macierz, znormalizuj wektor itp.
Byłem ciekawy, jaka jest „najlepsza praktyka” dla tego rodzaju funkcji ... To znaczy, czy powinienem uczynić funkcję funkcją składową, czy też nie-członkiem? (Dla zachowania przejrzystości / wykorzystania biblioteki)
Przykład:
//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);
Czy istnieje jakiś standard dotyczący tego rodzaju operacji? A przynajmniej czy istnieje jakiś powszechny sposób, w jaki ludzie to robią? Skłaniam się ku pierwszej opcji, ale chciałbym wiedzieć, czy jest to zalecane.
Zarówno funkcje członka, jak i nie będące członkami mają realne zalety oprócz zwykłego smaku. Na przykład, podstawowa tablica (tablice) zastosowana do implementacji
matrix
klasy prawdopodobnie będzieprivate
więc musiała być używana,friend
chyba że użyjesz funkcji członka. Pod tym względem projekt OO może być lepszy.Należy jednak pamiętać, że od czasu do czasu informatycy muszą wdrażać złożoną formułę matematyczną, nie zawsze wiedząc, co naprawdę robią. Kiedy muszę to robić, wolę funkcje nie będące członkami, ponieważ wynik „wizualny” będzie bliższy oryginalnej formule matematycznej (ponieważ formuła matematyczna zazwyczaj używa stylu funkcjonalnego).
Ostatecznie odpowiedź jest taka sama jak u Doc Browna: to kwestia gustu. Krótko mówiąc, możesz rozważyć napisanie biblioteki w stylu OO z funkcjami składowymi (łatwiejsze pisanie, nie
friend
), a następnie napisanie funkcji niebędących członkami w celu wykonania tych samych zadań, które po prostu przekażą swoje argumenty do członków. Pozwala zachować spójność i pozwolić użytkownikowi wybrać to, co uważa za najlepsze.źródło
Jeśli zanurzysz się głębiej w opisie problemu, jasne jest, że w pewnym momencie użyjesz niestandardowych struktur danych, które reprezentują określone byty matematyczne. Na przykład możesz reprezentować macierz jako środek n-wymiarowej tablicy. Aby rozwinąć swój przykład,
(Przykład w C ++ jest uproszczony, możesz użyć szablonów itp.)
Należy wziąć pod uwagę łatwość użycia niestandardowych struktur danych w obu przypadkach. C ++ (lub dowolny obiekt zorientowany) jako język jest sam w sobie potężniejszy i rozciąga się na konsumenta biblioteki w takim stopniu, w jakim przynosi korzyść implementatorowi. W przeszłości korzystałem tylko z bibliotek C, a te niestandardowe struktury danych zdają się być wszędzie dostępne w mgnieniu oka! Podczas gdy interoperacyjność jest łatwiejsza do osiągnięcia z tym drugim (może przy użyciu specjalnych konstruktorów?)
Na zakończenie, jeśli używasz C ++, zdecydowanie zalecane jest podejście obiektowe.
źródło
transpose
przykładami. Głównym powodem, dla którego C ++ jest łatwiejszy, jest fakt, że semantyka kopiowania i przypisywania faktycznie działa.A = B
może skompilować w C, ale prawdopodobnie robi coś złego.