0

グラフを扱うプログラムを書いています。私は2種類のグラフを扱っています.「抽象グラフ」はエッジを持つ抽象的な頂点で構成され、「平面グラフ」は頂点が平面内の座標x、yを持っています(実際には複雑な接辞zを使用していますしかし、それは問題ではありません)。

Vertex.h ファイルで次のように (抽象) Vertex クラスと派生クラス Planar_Vertex を作成することにしました。

class Vertex
{
public:
    Vertex();
    int get_label();
    void set_label(int label);
    void add_neighbor(int label);
    bool is_neighbor(int label);
    // etc
protected:
    int _label;
    std::vector<int> _list_neighbors;
};


class Planar_Vertex : public Vertex
{
    complex<double> _affix;
public:
    Planar_Vertex();
    Planar_Vertex(Vertex& V, complex<double> affix);
    complex<double> get_affix();
    void set_affix(complex<double> affix);
};

これが私の主な質問です。Planar_Vertex(Vertex& V, complex affix) コンストラクターに次の効果を持たせたい: 1. ラベルと近傍のリストが V と同じで、接辞が指定されている Planar_Vertex を出力する。ここまでは、簡単です。2. V がまさにこの新しいオブジェクトの基礎となる抽象的な頂点であることを望みます。つまり、main.cpp ファイルに次のように記述したとします。

Vertex V1;
...
Planar_Vertex V2(V1,z)

次に、V2 での set_label() の使用が V1 にも影響することを望みます (たとえば)。私が見ているように、このコンストラクターでは、次のように言いたいと思います: (メモリ内の) V のアドレスを、構築された Planar_Vertex のアドレスと同じにします (そして、以前に V に割り当てられたメモリを解放します)。ただし、メモリ内の変数の場所を変更することはできないようですので、どうすればよいかわかりません。私はC++に比較的慣れていないので、新しい配置、std::move、右辺値などについて読んで迷っています。

[編集: 要約すると、既に構築されている基本クラスのオブジェクトの上に派生クラスのオブジェクトを構築できるようにしたい。]

さて、私はグラフの実装について皆さんに多くのことを話したので、それについてあなたの意見を聞かせていただけるように残りをお話ししたいと思います。気にしないでください。明らかに、私の最初の質問に対する答えがすでにわかっている場合は、以下を読む必要はありません。先ほど言ったように、抽象頂点で構成される「抽象グラフ」と、平面頂点で構成される平面グラフを扱っています。

私の Graph.h ファイルは次のようになります。

class Graph
{
public:
    Graph();
    virtual ~Graph();
    virtual std::vector<Vertex*> get_list_vertices();
    void add_edge(int label1, int label2);
    virtual void add_vertex(Vertex&);
    // etc
};

class Abstract_Graph : public Graph
{
    std::vector<Vertex*> _list_vertices;
public:
    Abstract_Graph();
    ~Abstract_Graph();
    std::vector<Vertex*> get_list_vertices();
    void add_vertex(Vertex& V);
    // etc
};

class Planar_Graph : public Graph
{
    std::vector<Planar_Vertex*> _list_planar_vertices;
public:
    Planar_Graph();
    ~Planar_Graph();
    std::vector<Vertex*> get_list_vertices();
    std::vector<Planar_Vertex*> get_list_planar_vertices();
    void add_vertex(Planar_Vertex& V);
    // etc
};

私の考えでは、基本クラス Graph はインスタンス化されませんが、この基本クラスの関数として「抽象グラフ操作」を実装でき、Abstract_Graph オブジェクトと Planar_Graph オブジェクトの両方で機能します。これは、純粋な仮想関数 get_list_vertices のおかげで可能になりました。これは物事を行うための合理的な方法ですか?あなたは何をしたでしょうか?

事前にご回答いただき、誠にありがとうございます。

4

1 に答える 1

0

Planar_Vertex クラスの Vertex オブジェクトへの参照 (またはポインター) を保持して、私が理解していれば、必要なことを行うことができます。
カットダウン デモ:

#include <iostream>

struct Vertex {
    int value;
};

struct Planar_Vertex: public Vertex {
    Vertex& vr;
    Planar_Vertex(Vertex& v): vr(v) {}
};

int main()
{
    Vertex v;
    v.value = 1;
    std::cout << v.value << std::endl;

    Planar_Vertex p = Planar_Vertex(v);
    p.vr.value = 2;
    std::cout << v.value << std::endl;
}

参照を使用する場合は、コンストラクターの初期化リストで初期化する必要があります。ポインターを使用すると、初期化方法の柔軟性が高まりますが、あらゆる場所で null ポインターについて心配する必要があります。

どちらの場合も、Vertex が Planar_Vertex よりも長く存続することを確認する必要があります。

(もう 1 つのオプションは、Planar_Vertex のメンバーとしてプレーン Vertex (参照またはポインターではない) を持つことです。Planar_Vertex のコンストラクターを介して初期化し、必要な場所で使用します。これにより、有効期間の要件が処理されますが、あなたのコード。)

2番目の部分については、根本的に間違っているとは思いませんが、投稿した内容だけで意見を述べるのは難しいです. 継承はこれを行う 1 つの方法であり、別の方法はテンプレートを使用することです。どちらがより適切かは、正確な要件 (およびこれらの両方の概念に精通している) によって異なります。

于 2012-05-01T05:53:31.883 に答える