2013-04-19 2 views
5

Я понимаю, что в общем программировании алгоритмы отделяются от контейнеров. Поэтому было бы бессмысленно реализовывать общий алгоритм как метод экземпляра (тот же алгоритм должен работать над несколькими конкретными классами, мы не хотим, чтобы все они наследовались от одной ABC, поскольку она экспоненциально увеличивала количество классов).Почему библиотека «Источники»() `) является глобальной функцией?

Но в случае source() функция в Boost Graph Library, я не понимаю, почему это глобальная функция, а не метод экземпляра класса графа.

Насколько я мог сказать, прочитав BGL source code, source(e, g) должен знать детали реализации графа и краевых объектов, передаваемых к нему; недостаточно знать только их интерфейсы .

Так что source() не является общим алгоритмом. Другими словами, он должен знать конкретный класс экземпляра графа. Тогда почему бы не поместить его в тот же класс, что и метод экземпляра? Разве это не было бы намного более чистым/менее запутанным, чем создание глобальной функции, которая должна быть настроена для каждого класса, на который она призвана?

UPDATE

Соответствующий исходный код:

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

Источник причины (a, b) не может быть специализирован на основе типов его параметров. Не все должно быть функцией-членом. Некоторые свободные функции можно рассматривать как часть интерфейса класса. Кроме того, может быть полезно использовать источник() в качестве прокладки. Не читая и не понимая код (который не доступен в течение 2 кликов ваших ссылок), я не мог сказать вам, что, поскольку я не использую библиотеку графов, но они могут быть предметом рассмотрения. В качестве альтернативы отправьте напрямую разработчикам BGL и спросите об их дизайнерском решении. Я надеюсь, что для этого есть веская причина. – Pete

+0

Есть ли причина, по которой это вас беспокоит? – Pete

+2

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

ответ

6

source(e, g) не является общим алгоритмом. Его часть интерфейса, обычно называемая концепцией в C++. Причиной быть не-членной функцией является то, что она может быть реализована неинтрузивно.

Скажите, например, что вы хотели std::multimap для реализации концепции IncidenceGraph. Если библиотеке графа требуется source(), чтобы быть членом функции, вам не повезло, так как std::multimap не предоставляет ее.

+0

Я уверен, что в этом причина. Но почему это плохо наследовать от 'multimap' и добавить' source' в качестве функции-члена? – max

+0

@max Неплохо, это просто не решает проблему создания 'std :: multimap'' IncidenceGraph' –

+0

Если я правильно вас понимаю, вы говорите о следующей ситуации. Предположим, что мне дан объект 'data', который является экземпляром' std :: multimap'. Я хочу интерпретировать «данные» как график, обрабатывая значения ключей как вершины графа, а его отображаемые значения - в виде списков смежности. Я понимаю, почему здесь работает отличный от функции-член. Но что произойдет, если я хочу рассматривать «данные» как график, используя две разные интерпретации? Затем мне нужно написать два набора нечленовских функций. Как избежать их столкновения друг с другом? Не требует ли BGL, чтобы все они находились в одном пространстве имен? – max

3

В C++, следует предпочесть не-другу функции, не являющиеся членами, где это возможно сделать. Если source может быть реализован с точки зрения публичных членов классов, для которых он предназначен, он должен быть вне класса.

Это не имеет ничего общего с созданием универсальных алгоритмов; он полностью связан с уменьшением количества кода, который имеет доступ к/может повредить внутреннее состояние частных членов класса.

+0

Спасибо. Это действительно функция, отличная от друга, потому что объект, к которому он обращается, имеет только публичные члены (на самом деле это структура).Однако я не думаю, что понимаю, почему эти участники преданы гласности. См. [Мой предыдущий комментарий] (http://stackoverflow.com/questions/16114616/why-is-boost-graph-librarys-source-a-global-function#comment23015326_16114616). – max

+0

@max зависит от того, предназначен ли класс/структура для предотвращения нарушения инварианта. В этом случае, возможно, две вершины, которые построена в структуре, не имеют реального инварианта, который должен поддерживаться (т. Е. Является законным, если они являются одной и той же вершиной?). Если нет инварианта, то почему члены должны быть частными? Последовательность? В качестве альтернативы, возможно, разработчики BGL не могли бы написать весь код клея. – Pete

Смежные вопросы