1

C++ をより深く理解するために、多数の有向グラフ ヘルパー関数を含むプログラムを作成しています。中心的なオブジェクトの 1 つはノードと呼ばれ、ノード間の移動距離の計算に役立つメンバー関数を持ちます。OOP 設計での C++ テンプレートの使用について、よりよく理解しようとしています。

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;

それはそこで私の問題を解決します。ただし、エッジを表す基になるマップ データ構造が int しか保持できないという問題は修正されません。次に考えたのは、クラス テンプレートを宣言することでした。

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

しかし、これも私には奇妙に思えました。これは、宣言と初期化が次のようになることを意味します

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

もし私が自分のプログラムのユーザーだったら、Node をエッジの重みを表す float 型にすぐには関連付けません。

では、この場合のテンプレートの最適または適切な使用法は何でしょうか? または、ここで正しいパスでもテンプレートを使用していますか? 私のクラス設計にはそもそも欠陥があり、C++ esk ではない可能性があります。ここでのフィードバックは大歓迎です。

4

1 に答える 1

1

これは非常にきれいなコードです:)。C++ へようこそ!

あなたがやりたいことは、テンプレート変数を使用してエッジの重みを保持することだと思います。次のようなものはどうでしょう。

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 宣言をクラスのトップに移動しました。通常、これらはファイルの先頭に配置されます。また、Parashift C++ FAQ である神聖な経典、特にconst correctness に関するセクションを参照することも役立つ場合があります。たとえば、コンパレータ メソッドには const Node& パラメータが必要です。

于 2013-08-07T06:58:02.727 に答える