首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C中结构多态性的最佳方法

C中结构多态性的最佳方法
EN

Stack Overflow用户
提问于 2013-08-24 18:54:51
回答 3查看 8.2K关注 0票数 13

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

1.让用户将向量对象传递给专用函数,如:

代码语言:javascript
运行
复制
Vector2Dt_Dot(Vec2Dt* vector1, Vec2Dt* vector2);

其中t是向量的类型。然而,这种方法的问题在于它不允许不同类型的交互,所以我不能说计算浮点vector2d和双vector2d的点积。第二种方法,我倾向的是:

2.让用户将向量对象作为空指针传递,以及它们的类型,如:

代码语言:javascript
运行
复制
Vector2D_Dot(void* vector1, unsigned vector1_type, void* vector2, unsigned vector2_type);

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

也许还有其他我不知道的解决方案,但是这些是我目前正在考虑的解决方案。你觉得最好的方法是什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-08-24 19:20:19

您可以做的是使用多态对象。定义如下结构:

代码语言:javascript
运行
复制
#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指针,检查它们各自的类型字段,并将它们转换为适当的类型化变量来访问有效负载数据。

代码语言:javascript
运行
复制
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字段以包含指向函数指针结构的指针。您将为您定义的每个类型的vector创建一个函数指针结构的对象,并使用它查找与给定向量一起使用的函数。这种方法非常接近于C++在幕后所做的工作。

票数 19
EN

Stack Overflow用户

发布于 2013-08-24 19:06:01

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

代码语言:javascript
运行
复制
int  xyz(int a, ...);

这种样式需要一个已定义的参数(在本例中为a ),然后是可以在运行时确定数据类型的任意数量的参数。

有关如何处理变量参数列表的完整说明,请参阅函数和对象:va_listva_startva_argsva_end

希望这能有所帮助。如果有关于va_list等的问题,请问。

票数 2
EN

Stack Overflow用户

发布于 2013-08-25 17:20:21

实际上,我所做的是:

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

代码语言:javascript
运行
复制
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等类型的大小之间的差异。然后每个派生类:

代码语言:javascript
运行
复制
#define DEFINE_VECTOR2D(type, name)\
typedef struct{\
Vector2D_Base vec_base;\
type x, y;\
} Vector2D##name\
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18422002

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档