преодолеть отсутствие полиморфизма в C - PullRequest
0 голосов
/ 04 февраля 2020

Я работаю над проектом, для которого строго требуется для реализации двух наборов функций в C с одинаковой сигнатурой, которые можно использовать из сиглы. c test файл. один набор предназначен для структуры данных, другой - для другой и несовместимой структуры данных. Поскольку в C отсутствует полиморфизм, невозможно вызвать функцию, имеющую две реализации с одинаковой сигнатурой в двух разных файлах заголовков (.h), и принять как должное, что вызов будет отнесен к правильной реализации функции, которая на самом деле способен управлять правильной структурой данных. Хорошо, я знаю, что это кажется невозможным и противоречивым, но ... вот и все ... Мне нужно объединить два общих c элемента, которые могут быть списком или динамическими c массив Обновление: в List.h ( dynamicArray находится в другом .h)

    typedef struct Node{
  void *data;
  struct Node *next, *prevNode;
} Node;

//typedef struct declaration List
typedef struct List {
  struct Node *top, *bot, *prev;
  int size;
} List;



//in the dynamicarray.h file:
typedef struct dynamicArray{
  void **array;
  size_t size;
  size_t capacity;
}dynArray;



//in the dynamicarray.h file:
void* merge(void *element1,void *element2, int parameters){
  void * returner;

  if (parameters==ARRAY) {
    returner= Array_Merge(element1,element2); // expected to receive two arrays
  }
  else {
    returner= List_Merge(element1,element2); // expected to reveice two lists
  }

  return returner;
}

Есть ли у вас какие-либо предложения для выполнения sh этого запроса? Спасибо.

Ответы [ 2 ]

1 голос
/ 04 февраля 2020

Вам нужно передать и тест, и указатель на вашу функцию, и некоторую функцию-обработчик вместе с аргументом (ами). В 'c' void * можно использовать вместо любого указателя. Для вас может работать что-то вроде следующего:

int mytest(void*(*function)(void *), int(*handler)(void *), void *arg) {
    if (handler(function(arg)))
       return OK;
    return FAIL;
}

Итак, вам просто нужно иметь отдельные функции-обработчики для массивов и списков и передавать их в функцию тестирования вместе с другими параметрами.

Отвечая на ваш последний комментарий

Я могу представить себе следующую схему.

List list1;
dyArray array1;

MergedList outList;
MergedArray outArray;
...

void *getNextArrayElement(dynArray *array){...}
void *getNextListElement(List *list){...}

int mergeAsList(void* el, void *list){   
   if (el == NULL)
      return 0;
   ListMember *mmb = malloc(sizeof(ListMember));
   mmb->el = el;
   mmb->next = ((MergeList*)list)->head;
   (MergeList*)mergeList->head = mmb;
    return 1;
}

int mergeAsArray(void *el, void *array) {
    if (el == NULL)
      return 0;
    if (((MergeArray *)array)->index) >= MAX)
       return 0;
    ((MergeArray *)array)[((MergeArray *)array)->index++] = el;
    return 1;
} 
int mergeAsSortedArray(void *el, void *array){...}
...

test(getNextArrayEelement, mergeAsList, &arraty1, &outList);
test(getNextListEelement, mergeAsList, &list1, &outArray);
...

int test (void *(get*)(void*), 
          int (merge*)(void *m1, void *result), 
          void *in, 
          void *out) {
   void *el = get(in);
   int res = merge(el, out);
   return res;
}

0 голосов
/ 04 февраля 2020

Указатели функций - это средство, с помощью которого вы выполняете sh это.

Указатели на функции - это то, что вы используете, если, например, вы хотите передать функцию в функцию сортировки, которая сообщает функции сортировки, как сравнивать два соседних члена. Такая функция сравнения позволяет вам предоставить обобщенную функцию сортировки, которая будет работать с коллекцией любого struct, поскольку вы можете изменить функцию сравнения для размещения любой структуры.

Рассмотрим следующий код сортировки:

typedef struct node{
  void* item;
  struct node* next;
} Node;

// Just an ordinary bubble sort
void sort(Node *start, bool greaterThan(void* a, void* b)) 
{ 
    int swapped, i; 
    Node *ptr1; 
    Node *lptr = NULL; 

    /* Checking for empty list */
    if (start == NULL) 
        return; 

    do
    { 
        swapped = 0; 
        ptr1 = start; 

        while (ptr1->next != lptr) 
        { 
            if (greaterThan(ptr1->item, ptr1->next->item))
            { 
                swap(ptr1, ptr1->next); 
                swapped = 1; 
            } 
            ptr1 = ptr1->next; 
        } 
        lptr = ptr1; 
    } 
    while (swapped); 
}

// Swap function used above
void swap(Node *a, Node *b) 
{ 
    void* temp = a->item; 
    a->item = b->item; 
    b->item = temp; 
} 

Чтобы использовать его, нам просто нужно определить полезную нагрузку для помещения в Node* item и функцию сортировки, чтобы указать, как упорядочивать элементы:

typedef struct {
   int  book_id;
   char title[50];
   char author[50];
   char subject[100];
   char ISBN[13];
} Book;

// Comparison function.
bool bookGreaterThan(void* left, void* right)
{
  Book* a = (Book*)left;
  Book* b = (Book*)right;

  return strcmp(a->title, b->title) > 0;
}

Наконец, вы отсортировал бы ваш список следующим образом:

// Pass a pointer to the first node in your list, and a function pointer to your comparer.
sort(pointerToMyList, bookGreaterThan);

Полный пример можно найти здесь .

См. также Возможно ли достичь полиморфизма во время выполнения в C

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...