是否可以从抽象/基础结构继承或在C中沿着这些线模拟某些东西?

时间:2016-01-13 21:33:02

标签: c inheritance struct

我目前正在使用一个使用由xyz坐标组成的结构的C程序,但有时这些坐标可能是指向量(力/速度类型,而不是数据结构),而在其他时候它可能指的是位置。我知道可以简单地使用一个结构来处理所有这些不同的条件,因为它们大多使用相同的数据类型(浮点数),但只是简单地保持我的数学组织(加上变量和结构名称)并防止事情变得混乱,有没有办法定义一个基本结构,它定义自己有三个浮点数,由另一个结构继承,更具体地定义结构应该是什么(如位置而不是速度等)?我知道C不是OOP,但似乎可以这样做这里是基础结构的样子:

struct ThreeDCartesianData
{
   float x;
   float y;
   float z;
};

更具体的结构将从中继承并可能定义额外的变量,或者为变量使用不同的名称。将使用多个位置结构,但我认为每组数据只有一个速度结构。我已经看到了类似的问题,但它们似乎都指的是更高级别的语言(C ++,C#等等)。

3 个答案:

答案 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} },xy。然后,代码的读者会知道您正在谈论z而不是velocity。如果你真的对它感到疯狂,你可以在某个实现文件中隐藏position,因此用户永远不能自己实例化general3d,因为他们应该使用general3dposition视情况而定;这对你手头的任务来说可能是合理的,也可能是不合理的。值得付出额外的努力。

编辑:我对变量重命名或者直接向同一个结构添加更多变量并不乐观,但我会在那时开始朝着不同设计的方向发展。

一方面,如果你有两个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);
}