C++ reinterpret_cast for derived class
Parent class:
template <clas开发者_运维知识库s T>
class Point
{
protected
T x;
T y;
};
Derived class:
template <class T>
class Point3DTopo: public Point <T>
{
protected:
T z;
Face <T> *face; //Points to any face
};
I would like to cast one object of the class PointsList to another object Points3DTopoList (and vice versa) where:
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
};
Is such conversion allowed?
Points3DTopoList <T> *pl = new Points3DTopoList <T> ();
...
PointsList <T> *pl = reinterpret_cast < PointsList <T> * > ( pl3D );
And the reverse conversion?
PointsTopoList <T> *pl = new PointsTopoList <T> ();
...
Points3DTopoList <T> *pl3D = reinterpret_cast < Points3DTopoList <T> * > ( pl );
A Face pointer of each Point3Topo will be initialized to NULL or will be undefined?
Such a cast isn’t allowed. This is a fundamental problem: you either have to convert via copying, or adapt your class definitions so that you have a ListOf<PointT, T>
, i.e. parametrized both on the point type and the type inside the point.
However, the class design is flawed anyway: you should not derive Point3D
from Point
, this violates the Liskov substitution principle (LSP) – or more generally: a 3D point is not a 2D point. Quite the opposite, in fact: a 2D point is a special case of the 3D point.
So if you want to have an inheritance here, it should go the other way (i.e. 2D inherits from 3D) but this would most likely also violate LSP, and is very awkward (since then your 2D point would have a redundant variable that’s always fixed). Simply put, there is no suitable inheritance relation between 2D and 3D points, they are distinct entities.
Just about the only thing reinterpret_cast guarantees is that casting from A* to B* then back to A* yields the original pointer. Using the intermediate B* for anything other than casting back to A* is undefined.
It's just Undefined Behavior both ways.
It could be sensible to provide a conversion from Points3DTopoList to PointsList given that Point3DTopo is derived from Point. Inheritance, which provides that conversion automatically, is a possibility, but I suspect your public interface requirements (omitted from the question) make it more of a hassle than an asset.
Example of providing a conversion path:
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;
};
This provides two conversion paths – normally you'd pick one and not provide the other. The conversion operator is an implicit conversion (in C++0x you can mark it explicit), while the named method isn't a "conversion" in technical terms (thus never applies for any implicit or explicit conversion), but is explicitly called and used that way.
You can also provide an explicit conversion with an explicit constructor in PointsList which accepts a Points3DTopoList, and this works in current C++ at the expense of inverting the dependency relationship from how it would normally lie: that is, PointsList would know and care about Points3DTopoList instead of the other way around.
However, it may make more sense for you provide a "generic-Point" container; that is, one which accepts any concrete Point-like type.
template<class Point>
struct GenericPointContainer {
private:
std::vector<Point> points;
};
The biggest strength here is methods of GenericPointContainer can use various features from derived classes of Point which aren't present in Point itself, yet still be instantiated on Point directly. This works because all methods aren't instantiated when a class template is instantiated, and a practical example is how std::reverse_iterator overloads operator+=, which only works for random access iterators, yet can be instantiated on non-random-access iterators, such as std::reverse_iterator<std::list<int>::iterator>.
Then various list classes may become simple typedefs, if they are even still required:
typedef GenericPointContainer<Point<int> > PointsList;
typedef GenericPointContainer<Point3DTopoList<int> > Points3DTopoList;
C++0x would really help you here with template typedefs (you could use a rebind in current C++, but that gets obtuse); as you can see I had to specify T for the typedefs, so it's not quite as general as otherwise.
I was answered already: C++ reinterpret cast?
And it's will be not slow, because only the poiners will be copied.
YOUR OWN CAST FUNCTION.
精彩评论