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 类的一个对象转换为另一个对象 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>在点类型和点内的类型上都有一个,即参数化。

但是,无论如何,类设计都是有缺陷的:你不应该派生Point3DPoint,这违反了Liskov 替换原则(LSP)——或者更一般地说:3D 点不是2D 点。恰恰相反,事实上:2D 点是 3D 点的特例。

所以如果你想在这里继承,它应该采用另一种方式(即 2D 从 3D 继承)但这很可能也会违反 LSP,并且非常尴尬(因为那时你的 2D 点将有一个始终固定的冗余变量)。简单地说,2D 和 3D 点之间没有合适的继承关系,它们是不同的实体。

于 2011-01-18T07:54:41.660 回答
1

reinterpret_cast 保证的唯一事情是从 A* 转换为 B* 然后再转换回 A* 会产生原始指针。将中间 B* 用于除强制转换回 A* 之外的任何事情是未定义的。

于 2011-01-18T07:54:48.660 回答
0

我已经得到了回答: C++ reinterpret cast?

而且它不会很慢,因为只会复制指针。

您自己的演员阵容。

于 2011-01-18T09:14:36.977 回答
0

这只是两种方式的未定义行为。

于 2011-01-18T07:57:05.957 回答
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;
};

这提供了两种转换路径——通常您会选择一种而不提供另一种。转换运算符是隐式转换(在 C++0x 中,您可以将其标记为显式),而命名方法在技术术语中不是“转换”(因此从不适用于任何隐式或显式转换),而是显式调用并以这种方式使用。

您还可以在接受 Points3DTopoList 的 PointsList 中使用显式构造函数提供显式转换,这在当前的 C++ 中有效,但代价是与通常的依赖关系反转:也就是说,PointsList 会知道并关心 Points3DTopoList反过来。

但是,提供“通用点”容器可能更有意义;也就是说,它接受任何具体的点状类型。

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 在模板类型定义方面确实可以帮助您(您可以在当前 C++ 中使用重新绑定,但这会变得迟钝);如您所见,我必须为 typedef 指定 T,因此它不像其他方式那样通用。

于 2011-01-18T08:30:32.837 回答