C ++ reinterpret_cast для производного класса - PullRequest
0 голосов
/ 18 января 2011

Родительский класс:

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 );

Указатель Face каждого Point3Topo будет инициализирован значением NULL или будет неопределенным?

Ответы [ 5 ]

1 голос
/ 18 января 2011

Почти единственное, что гарантирует reinterpret_cast, - это приведение от A * к B *, а затем обратно к A *, возвращает исходный указатель.Использование промежуточного значения B * для чего-либо, кроме возврата к A *, не определено.

1 голос
/ 18 января 2011

Такое приведение не разрешено. Это фундаментальная проблема: вам нужно либо конвертировать с помощью копирования, либо адаптировать определения классов так, чтобы у вас была ListOf<PointT, T>, т.е. параметризованная как для типа точки, так и для типа внутри точки.

Однако дизайн класса в любом случае несовершенен: вы не должны выводить Point3D из Point, это нарушает принцип подстановки Лискова (LSP) - или, в более общем случае: точка 3D равна не 2D точка. Напротив, фактически: точка 2D является частным случаем точки 3D.

Итак, , если вы хотите иметь наследование здесь, оно должно пойти другим путем (то есть 2D наследуется от 3D), но это, скорее всего, также нарушит LSP, и очень неловко (с тех пор ваша 2D точка будет иметь избыточную переменную, которая всегда фиксирована). Проще говоря, нет подходящих отношений наследования между 2D и 3D точками, они являются различными объектами.

0 голосов
/ 18 января 2011

Мне уже ответили: Переинтерпретация C ++?

И это не будет медленным, потому что будут скопированы только указатели.

ВАША СОБСТВЕННАЯ ФУНКЦИЯ CAST.

0 голосов
/ 18 января 2011

Может быть целесообразно обеспечить преобразование из Points3DTopoList в PointsList, учитывая, что Point3DTopo является производным от Point. Наследование, которое обеспечивает автоматическое преобразование, возможно, но я подозреваю, что ваши требования к общедоступному интерфейсу (не включены в вопрос) делают его более сложным, чем актив.

Пример предоставления пути конвертации:

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, а не наоборот.

Однако для вас может иметь смысл предоставить контейнер "generic-Point"; то есть тот, который принимает любой конкретный точечный тип.

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

Самым большим преимуществом здесь является то, что методы GenericPointContainer могут использовать различные функции из производных классов Point, которые отсутствуют в самой Point, но все же могут быть созданы непосредственно в Point. Это работает, потому что все методы не создаются при создании экземпляра шаблона класса, и практический пример - то, как std :: reverse_iterator перегружает оператор + =, который работает только для итераторов с произвольным доступом, но может быть создан на итераторах без случайного доступа, такой как std :: reverse_iterator :: iterator>.

Тогда различные классы списка могут стать простыми определениями типов, даже если они все еще требуются:

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

C ++ 0x действительно помог бы вам с шаблонами typedefs (вы можете использовать перепривязку в текущем C ++, но это становится тупым); как вы можете видеть, я должен был указать T для typedefs, поэтому он не такой общий, как в противном случае.

0 голосов
/ 18 января 2011

Это просто неопределенное поведение в обоих направлениях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...