使向量3D从向量ND派生,需要保留字段x y z [英] make vector 3D derived from vector ND, need to retain field x y z
问题描述
我有矢量3D课
class Vector3D{
public: float x; float y; float z;
//some functions, e.g. operator+ - * /
//some 3D-specific function
};
和向量N-D类.
template<int constSize> class VecFloatFix{
float database[constSize];
//some functions, e.g. operator+ - * /
};
我注意到两个类之间存在代码重复,所以我认为我应该将Vector3D
派生自VecFloatFix<3>
:-
I noticed that there is code-duplication between two classes, so I think I should make Vector3D
derived from VecFloatFix<3>
:-
class Vector3D : public VecFloatFix<3>{
//some 3D-specific function
};
一切似乎都不错,只是直接有很多用户代码可以访问Vector3D::x,y,z
.
Everything seems to be good, except that there are a lot of user code access Vector3D::x,y,z
directly.
是否可以在不破坏用户代码的情况下从VecFloatFix<3>
派生Vector3D
?
Is it possible to make Vector3D
derived from VecFloatFix<3>
while not break user's code?
我最好的猜测是:-
template<int constSize> class VecFloatFix{
union{
float database[constSize];
float x,y,z; ????? sound like a hack
}
//some functions, e.g. operator+ - * /
};
编辑:将x,y,z
硬编码为VecFloatFix
是不可持续的.
如果我有一个从VecFloatFix<2>
派生的新类Vector2D
,则Vector2D::z
可以正常编译(危险).
Hardcoding x,y,z
into VecFloatFix
is unsustainable.
If I have a new class Vector2D
that derived from VecFloatFix<2>
, Vector2D::z
will compile fine (dangerous).
推荐答案
由于它使用实现定义的行为,而且可能是未定义的行为,因此不能保证该方法能正常工作.一个明智的实现将可能达到预期的效果.
This is by no ways guaranteed to work as it uses implementation-defined and possibly undefined behaviour. A sensible implementation will probably behave as expected though.
template<int constSize>
class VecFloatFix{
public:
union {
float database[constSize];
struct {
int x, y, z;
};
};
};
这也使database
公开.没有找到解决方法,但是没什么大不了的,因为无论如何您提供operator[]
.
This also leaves database
public. Don't see a way around this, but no big deal since you provide operator[]
anyway.
假定constSize >= 3
.如果您需要较小的尺寸,则可以通过增加一些黑客来实现.所有向量都将具有x
y
和z
成员,但是只有3D及更高版本才能使用它们. 2D向量将仅具有x
和y
可用(z
的任何使用都可能导致错误),而1D向量将仅具有x
.请注意,我拒绝对以下任何情况承担责任.
This assumes constSize >= 3
. If you need smaller sizes, this is doable through a bit more hackery. All vectors will have x
y
and z
members but only 3D and above will have them all usable. The 2D vector will have only x
and y
usable (any use of z
is likely to result in an error) and the 1D vector will have just x
. Note I refuse to take responsibility for any of the following.
template<int constSize>
class VecFloatFix{
public:
union {
float database[constSize];
struct {
float x;
};
struct {
spacer<constSize, 1> sp1;
typename spacer<constSize, 1>::type y;
};
struct {
spacer<constSize, 2> sp2;
typename spacer<constSize, 2>::type z;
};
};
};
其中spacer
的定义方式如下:
template <int N, int M, bool enable>
struct filler;
template <int N, int M>
struct filler<N, M, true>
{
float _f[M];
typedef float type;
};
template <int N, int M>
struct filler<N, M, false>
{
struct nothing {};
typedef nothing type;
};
template <int N, int M>
struct spacer
{
filler<N, M, (N>M)> _f;
typedef typename filler<N, M, (N>M)>::type type;
};
试驾:
VecFloatFix<4> vec4;
VecFloatFix<3> vec3;
VecFloatFix<2> vec2;
VecFloatFix<1> vec1;
`smoke test`
vec3.database[0] = 42;
vec2.database[1] = 99;
std::cout << vec3.x << std::endl;
std::cout << vec2.y << std::endl;
// make sure `y` aliases `database[1]`
std::cout << & vec2.y << std::endl;
std::cout << & vec2.database[1] << std::endl;
// make sure sizes are as expected
std::cout << sizeof(vec4) << " " << sizeof (vec3) << " " << sizeof(vec2) << " " << sizeof(vec1) << std::endl;
这篇关于使向量3D从向量ND派生,需要保留字段x y z的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!