Say you have two things (spatial vector, color vector) that are conceptually different (pos in space vs color) yet they actually end up needing the same types of operations - overloaded plus, minus, scalar multiply.
开发者_运维问答A nice solution in the Cg programming language was they actually aliased member names .xyzw and .rgba. So in Cg you can do
float4 vector = float4( 4, 3, 2, 1 );
float red = vector.r ;
float x = vector.x ;
// both red and x will have the value 4.0.
So the question is: How do you deal with things that are conceptually different but programmatically the same? I could simply use a class Vector and "remember" that .x = .r, .y = .g and so on, which isn't that hard but appears somehow misleading.
The other option is to totally repeat the code in Vector and Color.
Which is better? Repeating code for readability's sake, or just living with the bad naming?
If you really want that kind of aliasing you can use unions, e.g.
struct Vec {
union {
float r;
float x;
};
...
};
Personally, I would probably have defined a vector type that used the ()
or []
operator for access and make SpatialVector
and ColorVector
typedefs. With indexed access you can easily iterate over the elements.
(Warning: The following advice comes from a Java programmer. :)
Seems like a good case for private inheritance or composition. Color
can expose a public interface with r()
, g()
, b()
etc., which simly delegate to a Vector
for their actual implementation. You probably wouldn't want to use public inheritance because in most cases Color
is not really a drop-in replacement for a Vector
.
If in fact most operations on Vector
are not useful on Color
(and vice versa), and all you're interested in is having an object with four properties, then perhaps one should not be implemented in terms of the other at all.
I'd reimplement the operations instead of sharing. But, ...
You could unions so that x and r share a value, y and g share a value, etc.
Or, implement float4 and make Color/Vector derived classes.
Since you're representing different concepts, I'd personally create different types. Clearer intent trumps avoiding repetitive code in my book.
Or if you wanted to turn the problem inside out, you could be even more general. Just use a plain old std::vector and access the different elements by index. In this case you lose a bit of the domain-specific context in exchange for more easily generalizable algorithms. Then you can make simple wrappers around it that offer the more conceptually correct members.
精彩评论