是否可以从抽象/基本结构进行继承,或者在C中沿着这些线进行模拟?
我目前正在使用一个C程序,该程序使用由xyz坐标组成的结构,但有时这些坐标可能指的是矢量(力/速度类型,而不是数据结构),而有时可能指的是位置。我知道可以对所有这些不同的条件简单地使用一个结构,因为它们都使用相同的数据类型(float),但是为了使我的数学更好地组织(加上变量和结构名称),避免混淆,有没有一种方法来定义一个基本结构,它将自己定义为有三个float,是否由另一个结构继承,该结构更具体地定义了该结构应该是什么(例如位置而不是速度等)?我知道C不是OOP,但似乎有可能做到这一点,基本结构是这样的:是否可以从抽象/基本结构进行继承,或者在C中沿着这些线进行模拟?,c,inheritance,struct,C,Inheritance,Struct,我目前正在使用一个C程序,该程序使用由xyz坐标组成的结构,但有时这些坐标可能指的是矢量(力/速度类型,而不是数据结构),而有时可能指的是位置。我知道可以对所有这些不同的条件简单地使用一个结构,因为它们都使用相同的数据类型(float),但是为了使我的数学更好地组织(加上变量和结构名称),避免混淆,有没有一种方法来定义一个基本结构,它将自己定义为有三个float,是否由另一个结构继承,该结构更具体地定义了该结构应该是什么(例如位置而不是速度等)?我知道C不是OOP,但似乎有可能做到这一点,基本结
struct ThreeDCartesianData
{
float x;
float y;
float z;
};
更具体的结构将继承自该结构,并可能定义额外的变量,或者为变量使用不同的名称。将使用多个位置结构,但我认为每组数据只有一个velocity结构。我见过类似的问题,但它们似乎都是指更高级的语言(C++、C#等)你可以使用
联合来解决这个问题。主struct
将包含一个“派生”结构的union
,以及一个“flag”字段,告诉您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;
您可以这样交替定义它们:
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;
然后像这样使用它们:
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;
如果联合体中的所有结构都具有相同类型的初始列表元素,且顺序相同,则标准允许您从任何子结构安全访问这些字段。使用typedef
s怎么样
typedef struct general3d {
float x;
float y;
float z;
} general3d_t;
typedef general3d position;
typedef general3d velocity;
这样,当你遇到velocity
类型的东西时,你将其编码为变量类型,但在引擎盖下,它仍然只有3个点,x
,y
,z
。然后,代码的读者就会知道你说的是速度
,而不是位置
。如果你真的想对它着迷,你可以将general3d
隐藏在某个实现文件中,这样用户就永远不能自己实例化general3d
,因为他们应该根据情况使用position
或velocity
;这对于你手头的任务来说可能是合理的,也可能不合理/值得付出额外的努力
编辑:我对变量重命名或将更多变量直接添加到同一个结构中不持肯定态度,但我会开始朝着不同的设计方向前进
一方面,如果有两个struct
s具有相同的底层类型,但需要不同的名称,那么可能只有两个独立的struct
s。例如:
struct point3d {
float x;
float y;
float z;
};
struct person {
float age;
float weight;
float salary;
};
是的,这两个都是3个浮动,但它们的理解非常不同,如果其中一个发生变化,它们应该能够自行改变。也许我想在人物
中添加一个姓名
字段,但是点3d
上的字符*
没有合理的类比。如果它们有不同的含义,只需分别定义它们
至于添加更多变量,这听起来像是包含其他struct
s的struct
s:
struct point3d {
float x;
float y;
float z;
};
struct person {
point3d position;
float age;
float weight;
float salary;
};
// access like:
person.position.x;
我以前做过这种事。我在派生类型结构的前面嵌入了基类型的副本。这更接近于模仿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);
}
这些有帮助吗,为什么不使用两个typedef
s呢?我的C有点生疏,经常使用Java,除了使用许多相同类型的结构和数学函数之外。除此之外,我的C经验仅基于我3年前C++的经验。基本上,这些被描述的事情中的一些对我来说并不重要。我知道TyPulf也用在C++中,但是我不记得经常用到它。@ KayLUM他们有点帮助,但是我在这里问的更具体一些。这些答案确实有帮助。到目前为止,我真的很喜欢这两个答案。他们都用不同的方法回答了我的问题。如果我两个都喜欢,我如何选择一个作为最佳答案?一个完美地回答了这个问题,另一个是我尝试做的一个很好的替代方案。这基本上是说你有一个从主结构继承的结构,除了x,y和z,它还有另一个叫做x1的变量?你有一个主结构,包含公共字段以及派生结构的并集x1
是其中一个派生结构的成员。那么它更像是合并两个不同的结构,而不是一个继承另一个?但是有同样的效果吗?@cluemein基本上是的。这是如何回答OP中的这部分问题的并不明显:“一个更具体的结构将继承它,并可能定义额外的变量,或者为变量使用不同的名称。”对,所以我想typedef
s解决了大部分问题。不同的变量名听起来就像两个不同的struct
s碰巧有相同的类型-分别定义它们以保持清晰,;而且更多的变量听起来像是包含其他struct
s的struct
s。不是nit,而是在您的第一个代码块中,typedef
s似乎是颠倒的[由于键入错误]。您是否希望(例如)typedef general3d位置
而不是typedef位置general3d
?而且,该块的顶行不应该前面有typedef
(例如typedef struct general3d…
)?@CraigEstey可能完全正确-我只是在写我的头顶,而且