【问题标题】:Best approach for struct polymorphism in C [closed]C中结构多态性的最佳方法[关闭]
【发布时间】:2013-08-24 18:54:51
【问题描述】:

我正在编写一个简单的二维矢量对象。它将具有 x 和 y 分量,以及长度、叉积等方法。问题是,我希望结构具有许多可能的类型(char、int、float、double 等)。我想知道在设计方面与对象交互的最佳选择是什么?这是我目前正在考虑的:

1.让用户将矢量对象传递给专门的函数,例如:

Vector2Dt_Dot(Vec2Dt* vector1, Vec2Dt* vector2);

其中“t”是向量的类型。但是,这种方法的问题是它不允许不同类型相互交互,所以我不能说计算浮点向量2d 和双向量2d 的点积。第二种方法,以及我的倾向:

2。让用户将向量对象作为 void 指针及其类型传递,例如:

Vector2D_Dot(void* vector1, unsigned vector1_type, void* vector2, unsigned vector2_type);

显然,这种方法在 API 方面更紧凑,也解决了上述问题,但代价是一些额外的参数和类型安全。

可能还有其他我不知道的解决方案,但这些是我目前正在考虑的解决方案。您认为最好的方法是什么?

【问题讨论】:

  • @WhozCraig 问题被标记为c,而不是c++
  • 不要使用void *替代;有太多方法可以使编译器无法捕捉到错误(因为任何指针类型都可以转换为 void *,在 C 或 C++ 中)。曾经,这个问题(简要地)有一个 C++ 标记,并且在较长时间内使用 C++ 引用类型表示法。如果 C++ 是相关的,请考虑 vector<vector<yourtype> >
  • @johnathan leffler:是的,那是我的错误。我经常在 C 和 C++ 之间切换。如果它是 C 中的一个选项,我肯定会使用类似矢量的接口。

标签: c


【解决方案1】:

您可以做的是使用多态对象。像这样定义结构:

#define INT_TYPE 0
#define DOUBLE_TYPE 1
//more type constants

typedef struct Vector2D {
    int type;
} Vector2D;

typedef struct Vector2D_int {
    Vector2D super;
    int x, y;
} Vector2D_int;

typedef struct Vector2D_double {
    Vector2D super;
    double x, y;
} Vector2D_double;

//more typed vector structures

然后您可以编写函数来接受Vector2D 指针,检查它们各自的类型字段并将它们转换为适当的类型变量以访问有效负载数据。

double Vector2D_length(const Vector2D* vector) {
    if(vector->type == TYPE_INT) {
        const Vector2D_int* intVector = (Vector2D_int*)vector;
        return sqrt(intVector->x * intVector->x + intVector->y * intVector->y);
    }
    if(vector->type == TYPE_DOUBLE) {
        const Vector2D_double* doubleVector = (Vector2D_double*)vector;
        return sqrt(doubleVector->x * doubleVector->x + doubleVector->y * doubleVector->y);
    }
    //other cases follow
}

这是手工编码的多态性。您只需要确保 type 字段始终设置为正确的值(在创建类型化向量时设置一次)。

这种方法对您的第二个想法的优势在于,您不必在另一个变量中传递向量的类型,这会使使用向量变得乏味且容易出错。

作为替代方案,您可以定义 type 字段以包含指向函数指针结构的指针。您将为每个定义的向量类型类型创建此函数指针结构的一个对象,并使用它来查找要与给定向量一起使用的函数。这种方法将非常接近 C++ 在底层所做的工作。

【讨论】:

    【解决方案2】:

    你可以使用一个变量参数列表,它的原型被编码,例如:

    int  xyz(int a, ...);
    

    此样式需要一个已定义的参数,在本例中为 a,后跟任意数量的参数,其数据类型可在运行时确定。

    查看函数和对象:va_listva_start; va_args;和va_end,获取有关如何处理变量参数列表的完整说明。

    希望这会有所帮助。如有va_list等问题请追问。

    【讨论】:

      【解决方案3】:

      我实际使用的是以下内容:

      我创建了一个基本的 Vector2D 类,其布局如下:

      struct Vector2D_Base;
      typedef struct Vector2D_Base{
          M_double (*Vector2D_Get_X)(struct Vector2D_Base* vec);
          M_double (*Vector2D_Get_Y)(struct Vector2D_Base* vec);
      } Vector2D;
      

      如您所见,这允许泛型向量函数调用这些函数以将派生类的 x 和 y 值转换为双精度值,从而使泛型函数不必担心 char 和 float 等类型的大小差异.然后每个派生类:

      #define DEFINE_VECTOR2D(type, name)\
      typedef struct{\
      Vector2D_Base vec_base;\
      type x, y;\
      } Vector2D##name\
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-08
        • 2014-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多