2013-04-19 7 views
5

Rozumiem, że w programowaniu ogólnym algorytmy są oddzielane od kontenerów. Więc nie ma sensu implementować ogólnego algorytmu jako metody instancji (ten sam algorytm powinien działać na wielu konkretnych klasach, nie chcemy, aby wszystkie dziedziczyły z jednego ABC, ponieważ spowodowałby wykładniczy wzrost liczby klas).Dlaczego funkcja Boost Graph Library `source()` jest funkcją globalną?

Ale w przypadku funkcji source() w Boost Graph Library, nie rozumiem, dlaczego jest to funkcja globalna, a nie metoda instancji klasy wykresu.

O ile mogę powiedzieć, czytając BGL source code, source(e, g) musi znać szczegóły implementacji wykresu i krawędzi obiektów przekazanych do niej; nie wystarczy znać tylko ich interfejsów.

Tak więc source() nie jest ogólnym algorytmem. Innymi słowy, musi znać konkretną klasę instancji wykresu. Dlaczego więc nie umieścić go w tej samej klasie, co metoda instancji? Czy nie byłoby to o wiele czystsze/mniej dezorientujące niż tworzenie globalnej funkcji, która musi być dostosowywana do każdej klasy, do której jest przywoływana?

UPDATE

Odpowiedni kod źródłowy:

// dwa 09/25/00 - needed to be more explicit so reverse_graph would work. 
    template <class Directed, class Vertex, 
     class OutEdgeListS, 
     class VertexListS, 
     class DirectedS, 
     class VertexProperty, 
     class EdgeProperty, 
     class GraphProperty, class EdgeListS> 
    inline Vertex 
    source(const detail::edge_base<Directed,Vertex>& e, 
     const adjacency_list<OutEdgeListS, VertexListS, DirectedS, 
       VertexProperty, EdgeProperty, GraphProperty, EdgeListS>&) 
    { 
    return e.m_source; 
    } 


namespace boost { 

    namespace detail { 

    template <typename Directed, typename Vertex> 
    struct edge_base 
    { 
     inline edge_base() {} 
     inline edge_base(Vertex s, Vertex d) 
     : m_source(s), m_target(d) { } 
     Vertex m_source; 
     Vertex m_target; 
    }; 
    } 
} 
+0

Nie ma powodu, dla którego źródło (a, b) nie może być wyspecjalizowane w oparciu o typy jego parametrów. Nie wszystko musi być funkcją członka. Niektóre bezpłatne funkcje mogą być uważane za część interfejsu klasy. Dodatkowo przydatna może być funkcja source() jako podkładka. Bez czytania i zrozumienia kodu (który nie jest dostępny w ciągu 2 kliknięć linków), nie mogłem ci tego powiedzieć, ponieważ nie korzystam z biblioteki grafów, ale mogą to być rzeczy do rozważenia. Ewentualnie wyślij bezpośrednio programistów BGL i zapytaj o ich decyzję projektową. Spodziewam się, że istnieje ku temu dobry powód – Pete

+0

Czy jest jakiś powód, dla którego ci to przeszkadza? – Pete

+2

http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197 –

Odpowiedz

6

source(e, g) nie jest ogólnym algorytmem. Jest to część interfejsu, zwykle nazywana koncepcją w C++. Powodem bycia funkcją nie będącą członkiem jest to, że można ją wdrożyć nieinwazyjnie.

Załóżmy na przykład, że chcesz std::multimap wprowadzić w życie koncepcję IncidenceGraph. Jeśli biblioteka wykresów wymagałaby funkcji składowej, to nie miałabyś szczęścia, ponieważ source() nie zapewnia jej.

+0

Jestem pewien, że to jest powód. Ale dlaczego nie jest tak, aby odziedziczyć po 'multimap' i dodać' source' jako funkcję składową? – max

+0

@max To nie jest złe, po prostu nie rozwiązuje problemu tworzenia 'std :: multimap' i' IncidenceGraph' –

+0

Jeśli dobrze cię rozumiem, mówisz o następującej sytuacji. Załóżmy, że otrzymałem obiekt 'data', który jest instancją' std :: multimap'. Chcę interpretować "dane" jako wykres, traktując kluczowe wartości jako wierzchołki wykresów, a ich odwzorowane wartości jako listy przyległości. Rozumiem, dlaczego pod tym względem funkcjonuje nie-członkowskie podejście do funkcji. Ale co się stanie, jeśli chcę potraktować "dane" jako wykres za pomocą dwóch różnych interpretacji? Następnie muszę napisać dwa zestawy funkcji nie będących członkami. Jak uniknąć ich kolizji ze sobą? Czy BGL nie wymaga, aby wszystkie znajdowały się w tym samym obszarze nazw? – max

3

W C++, trzeba wolą funkcji non-Friend spoza UE, gdzie jest to możliwe, aby to zrobić. Jeśli source może być zaimplementowany pod względem publicznych elementów klas, to jest przeznaczony do działania, powinien znajdować się poza klasą.

Nie ma to nic wspólnego z tworzeniem ogólnych algorytmów; chodzi wyłącznie o zmniejszenie ilości kodu, który ma dostęp do/może uszkodzić stan wewnętrzny prywatnych członków klasy.

+0

Dzięki. Jest to rzeczywiście funkcja nie będąca przyjacielem, ponieważ obiekt, do którego ma dostęp, ma tylko członków publicznych (w rzeczywistości jest to struktura).Jednak nie sądzę, żebym rozumiał, dlaczego ci członkowie zostali upubliczni. Zobacz [mój wcześniejszy komentarz] (http://stackoverflow.com/questions/16114616/why-is-boost-graph-librarys-source-a-global-function#comment23015326_16114616). – max

+0

@max zależy od tego, czy klasa/struktura ma zapobiegać naruszeniu niezmiennika. W tym przypadku, być może dwa wierzchołki, które posiada struktura, nie mają prawdziwego niezmiennika, który musi zostać zachowany (tj. Jest legalny, jeśli są one tym samym wierzchołkiem?). Jeśli nie ma niezmienników, to dlaczego członkowie muszą być prywatni? Konsystencja? Alternatywnie może się zdarzyć, że programiści BGL nie będą mieli problemu z napisaniem całego kodu kleju. – Pete

Powiązane problemy