我目前正在使用一个使用由xyz坐标组成的结构的C程序,但有时这些坐标可能是指向量(力/速度类型,而不是数据结构),而在其他时候它可能指的是位置。我知道可以简单地使用一个结构来处理所有这些不同的条件,因为它们大多使用相同的数据类型(浮点数),但只是简单地保持我的数学组织(加上变量和结构名称)并防止事情变得混乱,有没有办法定义一个基本结构,它定义自己有三个浮点数,由另一个结构继承,更具体地定义结构应该是什么(如位置而不是速度等)?我知道C不是OOP,但似乎可以这样做这里是基础结构的样子:
struct ThreeDCartesianData
{
float x;
float y;
float z;
};
更具体的结构将从中继承并可能定义额外的变量,或者为变量使用不同的名称。将使用多个位置结构,但我认为每组数据只有一个速度结构。我已经看到了类似的问题,但它们似乎都指的是更高级别的语言(C ++,C#等等)。
答案 0 :(得分:3)
您可以使用union
。您的主struct
将包含union
"派生"结构以及标志"告诉你哪个联盟成员有效的字段:
enum { DERIVED11, DERIVED2, DERIVED3 };
struct derived1 { int x1; };
struct derived2 { char x2; };
struct derived3 { float x3; };
struct ThreeDCartesianData
{
float x;
float y;
float z;
int derivedType;
union {
struct derived1 d1;
struct derived2 d2;
struct derived3 d3;
} derived;
};
然后你可以像这样使用它们:
struct ThreeDCartesianData data1;
data1.x=0;
data1.y=0;
data1.z=0;
data1.derivedType = DERIVED1;
data1.derived.d1.x1 = 4;
你可以像这样定义它们:
struct common
{
int type;
float x;
float y;
float z;
};
struct derived1
{
int type;
float x;
float y;
float z;
int x1;
};
struct derived2
{
int type;
float x;
float y;
float z;
char x2;
};
struct derived3
{
int type;
float x;
float y;
float z;
float x3;
};
union ThreeDCartesianData {
struct common c;
struct derived1 d1;
struct derived2 d2;
struct derived3 d3;
};
并像这样使用它们:
union ThreeDCartesianData data1;
data1.c.type=DERIVED1;
data1.d1.x=0;
data1.d1.y=0;
data1.d1.z=0;
data1.d1.x1 = 4;
如果联合中的所有结构都具有相同顺序的相同类型的初始列表元素,则该标准允许您安全地从任何子结构访问这些字段。
答案 1 :(得分:3)
如何使用typedef
?
typedef struct general3d {
float x;
float y;
float z;
} general3d_t;
typedef general3d position;
typedef general3d velocity;
这样,当您遇到“velocity
类型的内容”时,您会将其编码为变量类型,但在引擎盖下,它仍然只有3个点,{{1} },x
,y
。然后,代码的读者会知道您正在谈论z
而不是velocity
。如果你真的对它感到疯狂,你可以在某个实现文件中隐藏position
,因此用户永远不能自己实例化general3d
,因为他们应该使用general3d
或position
视情况而定;这对你手头的任务来说可能是合理的,也可能是不合理的。值得付出额外的努力。
编辑:我对变量重命名或者直接向同一个结构添加更多变量并不乐观,但我会在那时开始朝着不同设计的方向发展。
一方面,如果你有两个velocity
具有相同的基础类型但需要不同的名称,那么你可能只有两个单独的struct
。例如:
struct
是的,这些都是3个花车,但他们的理解是非常不同的,如果其中一个或另一个发生变化,他们应该能够自行改变。也许我想在struct point3d {
float x;
float y;
float z;
};
struct person {
float age;
float weight;
float salary;
};
添加name
字段,但person
上的char *
没有合理的类比。如果它们意味着不同的东西,请单独定义它们。
至于添加更多变量,听起来像point3d
s包含其他struct
s:
struct
答案 2 :(得分:1)
我以前做过这种事。我在派生类型struct的前面嵌入了基类型的副本。这更接近于模仿c++
可能做的事情。以下是我使用的两种方法。
使用简单类型:
#define XYZDEF \
int type; \
float x; \
float y; \
float z
// base type
struct xyzdata {
XYZDEF;
};
// derived type 1
struct vector {
XYZDEF;
int vector_info;
...
};
// derived type 2
struct position {
XYZDEF;
int position_info;
...
};
#define BASEOF(_ptr) \
((struct xyzdata *) (_ptr))
// vector_rotate -- rotate a vector
void
vector_rotate(vector *ptr)
{
}
// position_rotate -- rotate a position
void
position_rotate(position *ptr)
{
}
// xyzrotate -- rotate
void
xyzrotate(xyzdata *ptr)
{
switch (ptr->type) {
case TYPE_POSITION:
vector_rotate((vector *) ptr);
break;
case TYPE_VECTOR:
position_rotate((position *) ptr);
break;
}
}
使用虚函数表指针:
#define XYZDEF \
int type; \
vtbl *vtbl; \
float x; \
float y; \
float z
// forward definitions
struct xyzdata;
struct vector;
struct position;
// virtual function table
struct vtbl {
void (*rotate)(struct xyzdata *);
};
// base type
struct xyzdata {
XYZDEF;
};
// derived type 1
struct vector {
XYZDEF;
int vector_info;
...
};
// derived type 2
struct position {
XYZDEF;
int position_info;
...
};
#define BASEOF(_ptr) \
((struct xyzdata *) (_ptr))
// vector_rotate -- rotate a vector
void
vector_rotate(struct xyzdata *ptr)
{
struct vector *vec = (void *) ptr;
...
}
// position_rotate -- rotate a position
void
position_rotate(struct xyzdata *ptr)
{
struct position *pos = (void *) ptr;
...
}
// xyzrotate -- rotate
void
xyzrotate(xyzdata *ptr)
{
ptr->vtbl->rotate(ptr);
}