В этом случае, как модулировать программу, а также добиться сокрытия информации? - PullRequest
0 голосов
/ 28 января 2019

Я создал два класса "DEVICE_s" и "DEVICE_SET_s" следующим образом:

Device_Manager.h

typedef struct DEVICE_s DEVICE_s;
typedef struct DEVICE_SET_s DEVICE_SET_s;

Device_Manager.c

struct DEVICE_s
{
    uint32_t IP;
    TYPE_e Type;
    METHOD_e Method;
    GROUP_RULE_e GroupRule;
    char Name[NAME_SIZE];
};
struct DEVICE_SET_s
{
    uint8_t     Total;
    uint8_t     Used;
    uint8_t     Available;
    DEVICE_s    Set[SET_SIZE];
};
DEVICE_s Instance;
DEVICE_SET_s Objects;

Потому что я поставилэти два класса в одном файле, все функции, которые манипулируют переменными «Instance» и «Objects», объединены внутри этого файла.

Я думаю, что этот способ плох, учитывая модульность, поэтому я хочу создать другой источникфайл для отдельного управления классом "DEVICE_SET_s", например:

DeviceSet_Manager.h

typedef struct DEVICE_SET_s DEVICE_SET_s;

DeviceSet_Manager.c

#include "Device_Manager.h"
#include "DeviceSet_Manager.h"
struct DEVICE_SET_s
{
    uint8_t     Total;
    uint8_t     Used;
    uint8_t     Available;
    DEVICE_s    Set[SET_SIZE];    //Oops! Incomplete Type Is Not Allowed
};

Однако, с точки зрения DeviceSet_Manager.c, класс "DEVICE_s" не виден (не полный тип).

Как это исправить?Спасибо

Ответы [ 2 ]

0 голосов
/ 28 января 2019

То, что вы хотите, это непрозрачные типы для

  • DEVICE
  • DEVICE_SET

Это одно и то же для обоих:

*Заголовок 1010 *

, определяющий

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

реализация

  • полный тип
  • интерфейсные функции

заголовки

device.h

#ifndef DEVICE_H
#define DEVICE_H

struct device;

struct device * device_new(void);
void device_delete(struct device *);

#endif

device_set.h:

#ifndef DEVICE_H
#define DEVICE_H

#include "device.h"

struct device_set;

struct device_set * device_set_new(size_t);
void device_set_delete(struct device_set *);

int device_set_set_device(struct device_set *, size_t, struct device *);
struct device * device_set_get_device(struct device_set *, size_t); 


#endif

реализации

device.c

#include "device.h"

struct device {
  ...
};

struct device * device_new(void)
{
  struct device * pd = malloc(sizeof * pd);
  if (NULL != pd)
  {
    /* Init members here. */
  }

  return pd;
}

void device_delete(struct device * pd)
{
  if (pd)
  {
    /* de-init (free?) members here. */
  }

  free(pd);
}

device_set.c:

#include "device_set.h"

struct device_set
{
  size_t total;
  size_t used;
  size_t available; /* what is this for? isn't it just total - used? */
  struct device ** pd;
}

struct device_set * device_set_new(size_t nb)
{
  struct device_set pds = malloc(sizeof *pds);
  if (NULL != pds)
  {
    pds->pd = malloc(nb * sizeof *pds->pd);
    if (NULL == pds->pd)
    {
      free(pds);
      pds = NULL;
    }
    else
    {
      for (size_t d = 0; d < nb; ++d)
      {
        pds->pd[d] = NULL;
      }

      pds->total = nb;
      pds->used = 0;
      pds->available = 0;
    }
  }

  return pds;
}

void device_set_delete(struct device_set * pds)
{
  if (pds)
  {
    free(pds->pd);
    free(pds)
  }

  return;
}

int device_set_set_device(struct device_set * pds, size_t d, struct device * pd)
{
  int result = 0;

  if (pds->total <= d)      
  {
    result = ERANGE;
  }
  else
  {
    pds->pd[d] = pd;
  }

  return;
}    

struct device * device_set_get_device(struct device_set * pds, size_t d); 
  int result = 0;
  struct device * pd = NULL;

  if (pds->total <= d)      
  {
    result = ERANGE;
  }
  else
  {
    pd = pds->pd[d];
  }

  return pd;
}
0 голосов
/ 28 января 2019

Вот что я обычно делаю:

device.h

// insert header guards here

typedef struct DEVICE_s DEVICE_s;
struct DEVICE_s
{
   ...
};

// method declarations here
DEVICE_Init(DEVICE_s * this, ...);
DEVICE_Foo(DEVICE_s * this, ...);

device.c

#include "device.h"
// method implementations here

deviceset.h

//hguards...

#include "device.h"

typedef struct DEVICE_SET_s DEVICE_SET_s;
struct DEVICE_SET_s
{
    uint8_t     Total;
    uint8_t     Used;
    uint8_t     Available;
    DEVICE_s    Set[SET_SIZE];
};

// method declarations here
DEVICE_SET_Init(DEVICE_SET_s * this, ...);
DEVICE_SET_Foo(DEVICE_SET_s * this, ...);

deviceset.c

#include "deviceset.h"
// method implementations here

usercode.c

DEVICE_SET_s myDevices;
void func(void) {
     DEVICE_SET_Init(&myDevices, a, b, c);         
        ...
}

При таком подходе пользователи несут ответственность за выделение памяти и вызов функции init (= constructor) для инициализации объекта перед использованием.

Это действительно не дает инкапсуляции, но дает максимальную свободу для распределения.Чтобы инкапсуляция работала хорошо, нужна поддержка языка.Поскольку C для начала настолько ограниченный язык, я не рекомендую добавлять больше ограничений только для удовлетворения парадигмы программирования.

...