【问题标题】:C - Polymorphic (void *) arraysC - 多态(void *)数组
【发布时间】:2014-10-27 22:48:33
【问题描述】:

我最近试图找出使用void * 数组而不是典型类型(intchar 等)的好处。所以我尝试编写一个多态 (void *) 函数,它接受任何类型数据的 3 个数组 (a, b, c) 作为参数,并在数组 ab 的每个节点之间进行计算,并将结果放入数组 @ 987654329@。计算的类型(sum、sub 等)和要计算的数据类型取决于用户(也许我们可以为函数使用另外两个参数)。

所以我的函数原型如下所示:

void *apply(void *a, void *b, void *c, int calc, int typeOfCalc);

我无法理解如何使用每个 void 数组的内容,具体取决于其类型,以及如何根据用户想要的数据类型进行计算。

编辑

我找到了一个练习,它问的问题和我一样,并说:

编写一个多态函数"apply",其参数相同 任何(每种)类型的元素的尺寸表(a,b,c),使 a [i] b [i] 之间的事务对于每个 i 并将结果 对 c[i] 采取行动。行为和结果将产生,被确定 调用者函数。

【问题讨论】:

  • 您必须将数组转换回正确的类型,具体取决于计算。因此,如果您的计算涉及浮点数,则必须将数组转换回浮点数。我猜typeOfCalc 传达了这些信息。
  • 这就是为什么我会避免使用“多态”数组...在某些地方您需要强制转换、复制和大量 IF...
  • 事实上,您所描述的行为在 C++ 中比在 C 中做得更好。如果您真的想要这种行为,并且如果您可以使用 C++,请改用它。
  • 我并不是真正的多态性粉丝,但这是我想知道的。 @Evert typeOfCalc 实际上是用户想要从计算中产生的。例如,在通话之前,我有 int a[5] = {1,2,3,4,5} 和 char b[5] = {'a','b','c','d','e '} 并且用户说希望将这两个数组的总和作为字符..
  • 检查man qsort,特别是例子。

标签: c arrays polymorphism void


【解决方案1】:

您可以使用函数指针而不是 typeOfCalc,它接收 a、b 和 c。因此,如果您想对浮点数求和,则传递一个“sumFloat”指针。您还可以将大量函数指针(sum、product 等)存储在结构中(例如,“operationsFloat”)并传递它。一些代码说明:

void sumFloat(void *a, void *b, void *c)
{
    float * f_a = a;
    float * f_b = b;
    float * f_c = c;

    *c = *a + *b;
}

void productFloat(void *a, void *b, void *c)
{
    float * f_a = a;
    float * f_b = b;
    float * f_c = c;

    *c = *a * *b;
}

typedef struct{
    void (*sum)(void *a, void *b, void *c);
    void (*product)(void *a, void *b, void *c);
}Operations;

Operations operationsFloat = {
        .sum = sumFloat,
        .product = productFloat,
};

void apply(void *a, void *b, void *c, char op, Operations * opClass){
    switch (op) {
        case '+':
            opClass->sum(a, b, c);
            break;
        case '*':
            opClass->product(a, b, c);
            break;
        default:
            break;
    }
}

【讨论】:

  • 嗯,我有点困惑。如何使用函数指针来确定用户想要的结果类型,以及现有数组的内容类型如何?我不认为我必须使用结构或其他东西..
  • 我添加了一些代码。现在,您可以添加整数运算、分数运算或任何您喜欢的。然而,我认为这个特定的例子并没有展示出你可以用函数指针做的所有美好的事情。
  • 好的,所以@Mabus 在您的示例中,当用户要求浮点结果时,数组也必须是浮点数,对吗?但是如果我想在 int 和 char 数组之间求和以获得浮点结果?
  • 好吧,这是一个非常不同的情况。在这种情况下,您可以传递三个函数指针:aToCommon、bToCommon 和 commonToC,其中“Common”是一种可以表示您想要并使用它们操作的所有值的类型。所以你把a和b转换成Common,用Common做运算,转换成c。
  • 好的,如果您查看我之前编辑的原始帖子,您实际上会看到相同练习的要求。我想我不知道 A 和 B 的类型,但我可以有几个参数来做我想做的任何事情。但主要思想(我想)是如何找出 2 个数组 A 和 B 的内容的类型,以及如何正确地对它们进行类型转换以进行我想要的计算
【解决方案2】:

这里是一个获取任意类型数组并使用回调函数的示例:

#include <stdio.h>

enum OP{SUM, SUB};

void calc_int(const void *pa, const void *pb, void *pc, enum OP op)
{
    switch (op) {
        case SUM:
            *(int *)pc = *(const int *)pa + *(const int *)pb;
            break;
        case SUB:
            *(int *)pc = *(const int *)pa - *(const int *)pb;
            break;
    }
}

void calc_double(const void *pa, const void *pb, void *pc, enum OP op)
{
    switch (op) {
        case SUM:
            *(double *)pc = *(const double *)pa + *(const double *)pb;
            break;
        case SUB:
            *(double *)pc = *(const double *)pa - *(const double *)pb;
            break;
    }
}

void calc(void *pa, void *pb, void *pc, size_t n, size_t size, enum OP op,
          void (cb)(const void *, const void *, void *, enum OP))
{
    char *a = (char *)pa;
    char *b = (char *)pb;
    char *c = (char *)pc;
    size_t i;

    for (i = 0; i < n; i++) {
        cb(a, b, c, op);
        a += size;
        b += size;
        c += size;
    }
}

int main(void)
{
    #define N 3
    int ia[N] = {1, 2, 3};
    int ib[N] = {4, 5, 6};
    int ic[N];
    double da[N] = {4., 5., 6.};
    double db[N] = {1., 2., 3.};
    double dc[N];
    int i;

    calc(ia, ib, ic, N, sizeof(*ia), SUM, calc_int);
    calc(da, db, dc, N, sizeof(*da), SUB, calc_double);

    for (i = 0; i < N; i++) {
        printf("ic[%d] = %d\n", i, ic[i]);
    }
    for (i = 0; i < N; i++) {
        printf("dc[%d] = %f\n", i, dc[i]);
    }   
    return 0;
}

【讨论】:

  • 我认为 OP 打算让 a、b 和 c 成为 n 个元素的数组,而不是一个将两个元素相加(或减去)的 2 元素数组。所以你可能想稍微调整一下你的例子。
猜你喜欢
  • 2014-04-10
  • 1970-01-01
  • 2012-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多