C ++ reinterpret_cast用于派生类

时间:2011-01-18 07:50:24

标签: c++ derived-class reinterpret-cast

家长班:

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还是未定义?

5 个答案:

答案 0 :(得分:1)

不允许这样的演员。这是一个基本问题:您必须通过复制进行转换,或者调整您的类定义,以便您拥有ListOf<PointT, T>,即在点类型和点内类型上进行参数化。

但是,课程设计仍有缺陷:你不应该从Point3D派生Point,这违反了Liskov substitution principle(LSP) - 或更普遍:3D点是 2D点。事实恰恰相反:2D点是3D点的特殊情况。

所以如果你希望在这里有继承,它应该采用另一种方式(即2D继承自3D),但这很可能违反了LSP,并且非常尴尬(从那以后你的2D点会有一个总是固定的冗余变量)。简而言之,2D和3D点之间没有合适的继承关系,它们是不同的实体。

答案 1 :(得分:1)

reinterpret_cast保证唯一的事情就是从A *转换为B *然后再转回A *会产生原始指针。使用中间B *除了回退到A *以外的任何东西都是未定义的。

答案 2 :(得分:0)

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

答案 3 :(得分: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中,您可以将其标记为显式),而命名方法在技术术语中不是“转换”(因此从不适用于任何隐式或显式转换),但是显式调用并以这种方式使用。

您还可以使用PointsList中的显式构造函数提供显式转换,该构造函数接受Points3DTopoList,这在当前的C ++中工作,代价是将依赖关系从通常的位置转换为依赖关系:也就是说,PointsList会知道并关心关于Points3DTopoList而不是相反。

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

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

这里最大的优势是GenericPointContainer的方法可以使用Point派生类中的各种特性,这些特性在Point本身中不存在,但仍然直接在Point上实例化。这是有效的,因为在实例化类模板时没有实例化所有方法,并且一个实际的例子是std :: reverse_iterator如何重载operator + =,它只适用于随机访问迭代器,但可以在非随机访问迭代器上实例化,例如std :: reverse_iterator&lt; std :: list&lt; int&gt; :: iterator&gt;。

然后,如果仍然需要,各种列表类可能会变成简单的typedef:

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

C ++ 0x真的会帮助你使用模板typedef(你可以在当前的C ++中使用重新绑定,但这会变得迟钝);正如你所看到的,我必须为typedef指定T,所以它不像其他那样通用。

答案 4 :(得分:0)

我已经回答:C++ reinterpret cast?

并且它不会很慢,因为只会复制poiners。

您自己的CAST功能。