Узел ориентированного графа C++ с реализацией шаблона

Я пишу программу, которая имеет множество вспомогательных функций Directed Graph, чтобы лучше понять C++. Один из центральных объектов называется Node, у которого есть функции-члены, помогающие вычислять расстояние между узлами. Я пытаюсь лучше понять использование шаблонов С++ в ООП-дизайне.

Вот краткий снимок класса Node

class Node {

    friend void swap(Node & first, Node & second) {
        using std::swap;
        swap(first.name, second.name);  
    }

public:

    Node(std::string val);

    Node(const Node & copy);

    Node & operator = (Node copy) {

        swap(*this, copy);
        return *this;

    }

    bool operator < (Node & rhs) const {
        return (size < rhs.size);
    }

    bool operator > (Node & rhs) const {
        return (size > rhs.size);
    }

    bool insertEdge(Node * dest, int distToNode);

    // I'd like for this return type to not be tied to an int
    // Especially if weights were represented as floats or doubles
    int findTravelDistance(Node * const & toNode) const;
    int findTravelDistance(std::queue<Node *> * const & nodeRoute) const;

    // Mutators
    void setNodeName(const std::string nameToSet);
    std::string getNodeName() const;

    void setNodeSize(const int size);
    int getNodeSize() const;

    // Misc
    void toString() const;

    // Constants
    static const bool ALLOW_CIRCULAR;

    ~Node();

protected:


private:
    int size;
    std::string name;
    // Here int represents the weight of the edge. I would like it to be able to be
    // declared as an int, float, long, or double etc...
    std::map<Node *, int> * travelEdges;

}; // end class

} // end namespace

По мере того, как я создаю этот класс, чтобы включить в него больше функций, я не могу понять, как сделать мои функции более адаптируемыми. Например, посмотрите на функции findTravelDistance.

Я хотел бы, чтобы тип возвращаемого значения, представляющий вес, не зависел от типа, а значение упорядоченной структуры данных карты не зависело от типа. Как это реализовано в настоящее время, пользователь может объявить только тип int для веса. Я понимаю, что могу приступить к перегрузке функций. Но я чувствую, что это было бы слишком избыточно и явным нарушением принципа DRY. Если бы мне пришлось изменить работу этой функции, мне пришлось бы менять ее для каждой перегрузки. Так что моя интуиция подсказывает мне, что я должен использовать шаблоны C++. Поскольку я новичок в шаблонах, я борюсь с тем, где его объявить. Если я сделаю свои функции шаблона функций поиска и просто верну общий тип..

template<class T>
T findTravelDistance(std::queue<Node *> * const & nodeRoute) const;

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

template<class T>
class Node { ... }

Но мне это тоже показалось странным. Это означало бы, что объявление и инициализация будут выглядеть примерно так

Node<float> * n = new Node<float>("N");

Если бы я был пользователем своей программы, я бы не стал сразу ассоциировать Node с типом float, представляющим веса ребер.

Итак, как лучше всего использовать шаблон в этом случае? Или использование шаблона здесь даже правильный путь? Возможно, мой дизайн класса с самого начала ошибочен и не очень C++'esk. Любая обратная связь здесь очень ценится.


person Paul Renton    schedule 07.08.2013    source источник


Ответы (1)


Это очень чистый код :). Добро пожаловать в С++!

Я считаю, что вы хотите использовать переменную шаблона для хранения весов ребер. Как насчет чего-то вроде следующего:

using std::swap;
template<class Distance>
class Node {

friend void swap(Node & first, Node & second) {  
    swap(first.name, second.name);  
}
public:

Node(std::string val);

Node(const Node & copy);

Node & operator = (Node copy) {

    swap(*this, copy);
    return *this;

}

bool operator < (Node & rhs) const {
    return (size < rhs.size);
}

bool operator > (Node & rhs) const {
    return (size > rhs.size);
}

bool insertEdge(Node * dest, Distance distToNode);

// I'd like for this return type to not be tied to an int
// Especially if weights were represented as floats or doubles
Distance findTravelDistance(Node * const & toNode) const;
Distance findTravelDistance(std::queue<Node *> * const & nodeRoute) const;

// Mutators
void setNodeName(const std::string nameToSet);
std::string getNodeName() const;

void setNodeSize(const Distance size);
int getNodeSize() const;

// Misc
void toString() const;

// Constants
static const bool ALLOW_CIRCULAR;

~Node();

private:
 int size;
std::string name;
std::map<Node *, Distance> * travelEdges;

}; // end class

В качестве бонуса я переместил ваши объявления using в начало класса. Обычно они идут вверху файла. Вам также может быть полезно взглянуть на священное писание, которое называется FAQ по Parashift C++, особенно раздел о константной корректности. Ваши методы компаратора, например, должны иметь параметры const Node&.

person jrs    schedule 07.08.2013
comment
Спасибо за ответ. Не могли бы вы объяснить, почему вы заменили параметр Node в реляционных операторных функциях (‹ и ›) классом-шаблоном? - person Paul Renton; 07.08.2013
comment
Извините, это была ошибка. Я исправил это. - person jrs; 08.08.2013