Hello world!
Working on some college-assignments, I've come to the point where I have a decent sized Vector3D class. I recently had to work on 2D, and thought of writing a simple wrapper over this class for the same. The thing looks something like:
Vector2D
{
private Vector3D m_backingVector;
Vector2D(float x, float y) { m_backingVector = new Vector3D(x,y,0.0f);
//Public functions implemented by calling into m_backingVector code.
}
Now, I understand that this has performance and memory implications, but for me, such a representation will help in easily translating all the 3D stuff I work on in the future to 2D, if applicable.
I have the following questions on this:
a) Is there a formal name to this pattern?
b) I get a different level of flexibility if I make a Vector2D by inheriting from a Vector3D, instead of containment. After all, a Vector2D IS a Vector3D, with the third coordinate always being 0. Do you guys think that modeling by inheritance is the way to go?
c) The one problem I see if I go with inheritance in b) is that it'll make me loose type-safety for my Vector2D's. <And that's not necessarily a bad thing...after all, a Vector2D IS a vector3D :D>, but, what I'd like to do, is prevent some operations from being called in Vector2D, that could be called in Vector3D. Is there a clean solution to this?
Update:
Inheritance seems better to me now, on second thought, but please do voice your comments for/against the same. I could also template Point and move common operations on it. That's the perfect solution, I guess, but that seems too much of a generalization.
I would have said the inheritance would be the other way around 2d is the base 3d is derived, because 2d is more general. 2d has members x and y, while 3d has x,y,z - so it makes sense for 3d to inherit from 2d.
Yes, I disagree about having 3d contained in a 2d class. That is not a 'has a' relationship.
The formal names are "IS A", "HAS A" and "USES A".
"IS A" implies inheritance.
"HAS A" means composition or containment as you call it. An example might be an Arc "HAS" CentrePt, BeginPt, EndPt - all of which are of a type CPoint say.
"USES A". means that an object uses another object, usually as a parameter in a function. A constructor for an Arc object might have PtOnArc, BeginPt, EndPt as parameters.
The inheritance solution is kind of messy because of the 3D functions you don't want replicated in the 2D class. I don't think there is a way of stopping these from coming through.
The wrapper class solution is almost as much work as writing a new 2D class from scratch. Most of the functions required are really short anyway.
There is a third way. Just use the 3D vector class directly in your 2D code. There are advantages to this. For example the well known lines crossing algorithm uses the cross product, with your vectors in the x,y plane you can examine the sign of the z-coordinate of the cross product to see if a point lies to the right or left of a line segment. With pure 2D vectors the cross product would not be available.
The inheritance solution is kind of messy because of the 3D functions you don't want replicated in the 2D class. I don't think there is a way of stopping these from coming through.
I think you are referring to the OP's inheritance design.
If the 3d inherits from the 2d ( IMO the only sensible way, as outlined above) then you can make 2d functions private so they don't come through to the 3d class. The other thing to do is make the functions virtual, then you can redefine the common ones in the 3d class. Think of the dot product function. I overloaded the * operator to do scalar & cross products, but had to have a function for dot product, unless I did something weird like overloading the comma operator to do dot product.
IMO from a purely mathematical standpoint, it doesn't make sense to have R^3 vectors be a kind of R^2 vectors. Inheritance translated in mathematical terms are algebraic structures, where the base classes are the more general AS, and the derived ones are more specific. E.g. Ring would derive from AbelianGroup.
Vector spaces are all fields. You can't perform more operations on R^3 than on R^2. Well, save for the cross product, which is unique to R^3 and not shared by any of the higher dimensions, further driving the argument that R^(n+1) is not a kind of R^n.
The way I'd do if I wanted to stay general would be
1 2 3 4 5
template <typename T,size_t N>
class vector{
T coord[N];
//...
};
This also avoid the overhead of inheritance, which is best avoided in such low-level types as vectors.
Thanks for the feedback, ideas and help guys...much appreciated.
I went ahead with 2D inheriting from the 3D class, purely because this was an academic project <read a very much dead-lined assignment :P>...in the future I know how to begin coding up my Vector classes!
@ideasMan - the other way round seems much more intuitive initially, but just consider this - a 2D vector IS A 3D vector with a 0 z. Can the same be said about a 3D vector? <Can we fit in a 3D vector being a type of a 2D vector somewhere - I couldn't think of any such relation>.
@Helios that's the best approach - I noted the same when working on this - so, I concur completely. A big +1 for attempting the inheritance hierarchy from scratch :).