2015-02-01 2 views
1

Проблема

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

Мой подход

алгоритмы происходят из

class SimilarityAlgorithm { 
public: 
    Base(const Graph& G); 

    virtual double run(node u, node v) = 0; // indices for nodes in the graph 

    virtual ScoreCollection& runAll() = 0; 
} 

Теперь алгоритмы отличаются в использовании памяти. Некоторые алгоритмы могут быть симметричными, а оценки для (u, v) и (v, u) идентичны. Для этого требуются разные типы ScoreCollection, которые должны быть возвращены. Примером может служить разреженная матрица и треугольная матрица, которые выводятся из ScoreCollection.

Это сводится к ковариантным типам возврата:

class SpecificAlgorithm : SimilarityAlgorithm { 
public: 
    double run(node u, node v); 

    // The specific algorithm is symmetric and thus uses a symmetric matrix to save memory 
    SymmetricScoreCollection& runAll(); 
} 

Вопрос

  • ли этот подход к дизайну хорошей идеи для этой проблемы?
  • Должен ли быть раскрыт факт, что все коллекции реализованы в виде матриц?
+0

Вы уверены, что хотите взять узлы по значению? И попытка ковариации должна работать. – Deduplicator

+0

Узлы на самом деле просто typedefs для unsigned long. Я думаю, что в этом случае ценность будет прекрасной. – xZA

+0

Несомненно, если это так, идентичность, вероятно, неважная. – Deduplicator

ответ

0

Ваш дизайн кажется подходящим для проблемы, которую вы описываете.

Проблема:

Однако, есть проблема с вашим SpecificAlgorithm: runAll() не возвращает тот же тип виртуальной функции базового класса. Поэтому он не будет вызываться (или, скорее всего, ваш код не будет компилироваться из-за отсутствия виртуальной функции).

Решение:

также использовать полиморфный подход к ScoreCollection, делая SymmetricScoreCollection производный класс ScoreCollection:

class SymetricScoreCollection: public ScoreCollection { 
//define the member functions to access the values virtual 
... 
}; 

class SpecificAlgorithm : public SimilarityAlgorithm { 
public: 
    double run(node u, node v); 

    // The specific algorithm is symmetric and thus uses a symmetric matrix to save memory 
    ScoreCollection& runAll(); 
};  

На самом деле это применение в factory method pattern, со следующими ролями :

  • СходствоАльгоритм - завод,
  • SpecificAlgorithm является бетонный завод
  • ScoreCollection является продуктом
  • SymetricScoreCollection является конкретный продукт

Дополнительное замечание:

Возвращение ссылки на ScoreCollection из runAll() приносит некоторые риски. Предположим, что sa - это конкретный алгоритм.

В следующем заявлении:

ScoreCollection sc = sa.runAll(); 

sa.runAll() возвращает ссылку на SymetricScoreCollection, но было бы скопировать упомянутый объект СБН, что делает его ScoreCollection. Slicing, и полиморфизм не сработает.

Следующее утверждение было бы, однако успеха:

ScoreCollection& rsc = sa.runAll(); 

потому что RSC является ссылкой, и он будет по-прежнему относятся к исходному SymetricScoreCollection объекта, возвращенного sa.runAll(), и все будет работать, как задумано.

Вы видите, что при возврате ссылок очень легко иметь незаметные ошибки. Я бы предложил вернуть указатель вместо ссылки.

+0

Благодарим вас за ответ. Что вы думаете о 'runAll()' return ** rvalue ссылках ** к объекту-члену? Это позволит вызывающему пользователю _steal_ объект из алгоритма. Я не упоминал об этом, но не хочу, чтобы алгоритм фактически сохранял результаты из 'runAll()'. В идеальном мире я хотел бы вернуться по значению, а также использовать ковариацию возвращаемых типов. Есть ли способ добиться чего-то подобного? – xZA

+0

В этом случае вы можете определить свою коллекцию для работы с элементами shared_ptr. – Christophe