0

親クラス:

template <class T>
class Point
{
    protected

        T x;
        T y;

};

派生クラス:

template <class T>
class Point3DTopo: public Point <T>
{
    protected:

        T z;
        Face <T> *face;   //Points to any face
};

クラスPointsListの1つのオブジェクトを別のオブジェクトPoints3DTopoListにキャストしたいと思います(またはその逆)。

template <class T>
class PointsList
{
  protected:
         std::vector <Point <T> *> points;  //Only illustration, not possible with   templaes
};


template <class T>
class Points3DTopoList
{
  protected:
         std::vector <Point3DTopo <T> *> points;  //Only illustration, not possible with   templaes
};

そのような変換は許可されていますか?

Points3DTopoList <T> *pl = new Points3DTopoList <T> ();
...
PointsList <T> *pl = reinterpret_cast < PointsList <T> * > ( pl3D );

そして逆変換?

PointsTopoList <T> *pl = new PointsTopoList <T> ();
...
Points3DTopoList <T> *pl3D = reinterpret_cast < Points3DTopoList <T> * > ( pl );

各Point3TopoのFaceポインターは、NULLに初期化されますか、それとも未定義になりますか?

4

5 に答える 5

1

このようなキャストは許可されていません。これは基本的な問題です。コピーによって変換するか、クラス定義を適合させてListOf<PointT, T>、つまり、ポイント タイプとポイント内のタイプの両方でパラメータ化する必要があります。

ただし、とにかくクラスの設計には欠陥があります。Point3Dから派生させるべきではありません。これはLiskov 代入原則(LSP)Pointに違反しています。より一般的には、3D 点は 2D 点ではありません。実際にはまったく逆です。2D 点は 3D 点の特殊なケースです。

したがって、ここで継承が必要な場合は、逆の方向に進む必要があります (つまり、2D は 3D から継承されます) が、これLSP に違反する可能性が高く、非常に厄介です (その場合、2D ポイントには常に固定されている冗長な変数があるため) )。簡単に言えば、2D ポイントと 3D ポイントの間に適切な継承関係はなく、それらは別個のエンティティです。

于 2011-01-18T07:54:41.660 に答える
1

reinterpret_cast が保証する唯一のことは、A* から B* にキャストしてから A* に戻すと、元のポインターが生成されることです。A* へのキャストバック以外の目的で中間 B* を使用することは定義されていません。

于 2011-01-18T07:54:48.660 に答える
0

それは両方の方法で未定義の動作です。

于 2011-01-18T07:57:05.957 に答える
0

私はすでに答えられました: C++はキャストを再解釈しますか?

ポインターのみがコピーされるため、遅くはありません。

あなた自身のキャスト機能。

于 2011-01-18T09:14:36.977 に答える
0

Point3DTopo が Point から派生していることを考えると、Points3DTopoList から PointsList への変換を提供することは理にかなっています。その変換を自動的に提供する継承は可能ですが、パブリックインターフェイスの要件(質問から省略)は、資産よりも面倒だと思います。

コンバージョン パスの提供例:

template<class T>
struct PointsList {
  // Points3DTopoList needs a way to construct a PointsList
  template<class Iter>
  PointsList(Iter begin, Iter end)
  : points(begin, end)
  {}

private:
  std::vector<Point<T> > points;
};

template<class T>
struct Points3DTopoList {

  operator PointsList<T>() const {
    return PointsList<T>(points.begin(), points.end());
  }

  PointsList<T> to_points_list() const {
    return PointsList<T>(points.begin(), points.end());
  }

private:
  std::vector<Point3DTopo<T> > points;
};

これにより、2 つのコンバージョン パスが提供されます。通常、一方を選択し、もう一方は指定しません。変換演算子は暗黙の変換です (C++0x では明示的とマークできます) が、名前付きメソッドは技術用語では "変換" ではありません (したがって、暗黙的または明示的な変換には適用されません) が、明示的に呼び出されます。そしてそのように使用しました。

また、Points3DTopoList を受け入れる PointsList の明示的なコンストラクターを使用して明示的な変換を提供することもできます。これは現在の C++ で機能しますが、通常の依存関係とは逆になります。逆に。

ただし、「generic-Point」コンテナを提供する方が理にかなっている場合があります。つまり、具体的な Point のような型を受け入れるものです。

template<class Point>
struct GenericPointContainer {
private:
  std::vector<Point> points;
};

ここでの最大の強みは、GenericPointContainer のメソッドが、Point 自体には存在しない Point の派生クラスからさまざまな機能を使用できることですが、Point で直接インスタンス化することもできます。これが機能するのは、クラス テンプレートがインスタンス化されるときにすべてのメソッドがインスタンス化されるわけではないためです。実用的な例として、std::reverse_iterator が operator+= をオーバーロードする方法があります。 std::reverse_iterator<std::list<int>::iterator> など。

その後、さまざまなリスト クラスが単純な typedef になる可能性があります。

typedef GenericPointContainer<Point<int> > PointsList;
typedef GenericPointContainer<Point3DTopoList<int> > Points3DTopoList;

C++0x は、ここでテンプレート typedef を使用するのに本当に役立ちます (現在の C++ では再バインドを使用できますが、それはわかりにくくなります)。ご覧のとおり、typedef に T を指定する必要があったため、他の方法ほど一般的ではありません。

于 2011-01-18T08:30:32.837 に答える