Pytanie Gdzie powinienem umieścić funkcje niezwiązane z klasą wywołało debatę na temat tego, czy w C ++ sens ma łączenie funkcji narzędziowych w klasie, czy po prostu ich istnienie jako wolnych funkcji w przestrzeni nazw.
Pochodzę z tła w języku C #, gdzie ta ostatnia opcja nie istnieje, a zatem naturalnie dąży do używania klas statycznych w małym kodzie C ++, który piszę. Najwyżej głosowana odpowiedź na to pytanie, a także kilka komentarzy mówi jednak, że preferowane są wolne funkcje, sugerując nawet, że klasy statyczne były anty-wzorcem. Dlaczego tak jest w C ++? Przynajmniej na pozór metody statyczne w klasie wydają się nie do odróżnienia od wolnych funkcji w przestrzeni nazw. Skąd więc taka preferencja?
Czy sytuacja wyglądałaby inaczej, gdyby zbiór funkcji narzędziowych potrzebował wspólnych danych, np. Pamięci podręcznej, którą można przechowywać w prywatnym polu statycznym?
źródło
Odpowiedzi:
Chyba muszę odpowiedzieć, że powinniśmy porównać intencje obu klas i przestrzeni nazw. Według Wikipedii:
Klasa
Przestrzeń nazw
Co teraz próbujesz osiągnąć, umieszczając funkcje w klasie (statycznie) lub w przestrzeni nazw? Założę się, że definicja przestrzeni nazw lepiej opisuje twój zamiar - wszystko, czego chcesz, to pojemnik na twoje funkcje. Nie potrzebujesz żadnych funkcji opisanych w definicji klasy. Zauważ, że pierwsze słowa definicji klasy to „ W programowaniu obiektowym ”, ale zbiór funkcji nie ma nic zorientowanego obiektowo.
Prawdopodobnie istnieją też powody techniczne, ale jako że ktoś pochodzący z Javy i stara się omijać język paradygmatu C ++, najbardziej oczywistą odpowiedzią jest dla mnie: Ponieważ nie potrzebujemy OO, aby to osiągnąć.
źródło
Byłbym bardzo ostrożny, nazywając to anty-wzorem. Przestrzenie nazw są zwykle preferowane, ale ponieważ nie ma szablonów przestrzeni nazw, a przestrzeni nazw nie można przekazywać jako parametrów szablonów, używanie klas zawierających wyłącznie elementy statyczne jest dość powszechne.
źródło
Wcześniej musiałem wziąć udział w zajęciach FORTRAN. Do tego czasu znałem inne imperatywne języki, więc pomyślałem, że mogę robić FORTRAN bez większego uczenia się. Kiedy oddałem swoją pierwszą pracę domową, profesor zwrócił mi ją i poprosił o jej powtórzenie: powiedział, że programy Pascala napisane w składni FORTRAN nie liczą się jako prawidłowe zgłoszenia.
Podobny problem występuje tutaj: używanie klas statycznych do hostowania funkcji narzędziowych w C ++ jest obcym idiomem dla C ++.
Jak wspomniałeś w swoim pytaniu, użycie klas statycznych dla funkcji narzędziowych w C # jest koniecznością: funkcje wolnostojące po prostu nie są opcją w C #. Język potrzebny do opracowania wzorca umożliwiającego programistom definiowanie funkcji wolnostojących w inny sposób - mianowicie w ramach statycznych klas użyteczności. To była sztuczka Java wykorzystana słowo w słowo: na przykład java.lang.Math i System.Math .NET są prawie izomorficzne.
Jednak C ++ oferuje przestrzenie nazw, inne narzędzie do osiągnięcia tego samego celu i aktywnie wykorzystuje je w implementacji swojej standardowej biblioteki. Dodanie dodatkowej warstwy klas statycznych jest nie tylko niepotrzebne, ale także nieco sprzeczne z intuicją dla czytelników bez tła w języku C # lub Java. W pewnym sensie wprowadzasz „tłumaczenie pożyczki” na język dla czegoś, co można wyrazić natywnie.
Kiedy twoje funkcje muszą współdzielić dane, sytuacja jest inna. Ponieważ twoje funkcje nie są już ze sobą powiązane , wzorzec Singleton staje się preferowanym sposobem spełnienia tego wymagania.
źródło
Być może musisz zapytać, dlaczego chcesz mieć klasę statyczną?
Jedynym powodem, dla którego mogę wymyślić, jest to, że inne języki (Java i C #), które są bardzo „wszystko jest klasą”, wymagają ich. Te języki w ogóle nie mogą tworzyć funkcji najwyższego poziomu, więc wymyślili sztuczkę, aby je zachować, i to była statyczna funkcja członka. To trochę obejście, ale C ++ tego nie potrzebuje, możesz bezpośrednio tworzyć zupełnie nowe, niezależne funkcje najwyższego poziomu.
Jeśli potrzebujesz funkcji, które działają na określonym elemencie danych, warto połączyć je w klasę, która przechowuje dane, ale wtedy przestają one być funkcjami i zaczynają być członkami tej klasy, które działają na danych klasy.
Jeśli masz funkcję, która nie działa na określonym typie danych (używam tego słowa, ponieważ klasy są sposobami do definiowania nowych typów danych), to naprawdę jest anty-wzorzec, aby umieścić je w klasie, nie inaczej niż cele semantyczne.
źródło
Innymi słowy posiadanie klasy zamiast przestrzeni nazw nie ma zalet.
Z jednej strony oszczędza ci ciągłego pisania na klawiaturze
static
, choć jest to prawdopodobnie niewielka korzyść.Główną zaletą jest to, że jest to najmniej wydajne narzędzie do pracy. Klasy mogą być używane do tworzenia obiektów, mogą być używane jako typ zmiennych lub jako argumenty szablonu. Żadna z tych funkcji nie jest pożądana dla twojej kolekcji funkcji. Dlatego lepiej jest użyć narzędzia, które nie ma tych funkcji, aby klasa nie mogła zostać przypadkowo wykorzystana.
Wynika z tego, że użycie przestrzeni nazw natychmiast pokazuje wszystkim użytkownikom kodu, że jest to zbiór funkcji, a nie plan tworzenia obiektów.
źródło
Klasa statyczna wykona zadanie, ale to tak, jakby jechać 53-metrową półciężarówką do sklepu spożywczego po frytki i salsę, gdy zrobi to czterodrzwiowy sedan (tj. Przesada). Zajęcia mają niewielki dodatkowy koszt, a ich istnienie może sprawić wrażenie, że zainicjowanie jednego może być dobrym pomysłem. Bezpłatne funkcje oferowane przez C ++ (i C, gdzie wszystkie funkcje są bezpłatne) tego nie robią; są tylko funkcjami i niczym więcej.
Nie całkiem. Pierwotnym celem
static
w C (a później C ++) było oferowanie trwałej pamięci masowej, która może być użyta na dowolnym poziomie zakresu:Możesz przenieść zakres na poziom pliku, dzięki czemu będzie widoczny dla wszystkich węższych zakresów, ale nie poza plikiem:
Prywatny członek klasy statycznej w C ++ służy temu samemu celowi, ale jest ograniczony do zakresu klasy. Technika zastosowana w
counter()
powyższym przykładzie działa również wewnątrz metod C ++ i jest to coś, co naprawdę poleciłbym zrobić, jeśli zmienna nie musi być widoczna dla całej klasy.źródło
Jeśli funkcja nie utrzymuje żadnego stanu i jest ponownie wprowadzana, wydaje się, że nie ma większego sensu wsuwanie jej do klasy (chyba że jest to wymagane przez język). Jeśli funkcja zachowuje pewien stan (np. Można ją zabezpieczyć tylko przed wątkami za pomocą statycznego muteksu), wówczas metody statyczne w klasie wydają się odpowiednie.
źródło
Znaczna część dyskusji na ten temat tutaj sens, choć nie jest czymś fundamentalnym o C ++, który sprawia, że
namespaces
iclass
es /struct
s bardzo różne.Klasy statyczne (klasy, w których wszyscy członkowie są statyczni, a klasa nigdy nie zostanie utworzona), same są obiektami. Nie zawierają one po prostu
namespace
funkcji.Szablon meta-programowania pozwala nam używać klasy statycznej jako obiektu do kompilacji.
Rozważ to:
Aby go użyć, potrzebujemy funkcji zawartych w klasie. Przestrzeń nazw nie będzie tu działać. Rozważać:
Teraz go użyć:
Tak długo, jak nowy alokator udostępnia kompatybilną funkcję
allocate
irelease
, przejście do nowego alokatora jest łatwe.Nie można tego osiągnąć za pomocą przestrzeni nazw.
Czy zawsze potrzebujesz funkcji, aby być częścią klasy? Nie.
Czy używanie klasy statycznej jest anty-wzorcem? To zależy od kontekstu.
W takim przypadku to, co próbujesz osiągnąć, prawdopodobnie najlepiej będzie osiągnąć poprzez programowanie obiektowe.
źródło
Jak słynie John Carmack:
„Czasami elegancka implementacja jest tylko funkcją. Nie metodą. Nie klasą. Nie strukturą. Po prostu funkcją.”
Myślę, że to podsumowuje. Dlaczego miałbyś uczynić z niej klasę, skoro wyraźnie nie jest klasą? C ++ ma luksus, że faktycznie można korzystać z funkcji; w Javie wszystko jest metodą. Potrzebujesz klas użytkowych i wielu z nich.
źródło