在这种情况下,如何实现程序的模块化和信息隐藏呢?
In this case, how to modularize program as well as achieving information hiding?
我创建了两个 classes "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;
因为我将这两个 class 放在同一个文件中,所有操作变量 "Instance" 和 "Objects" 的函数都放在这个文件中。
我认为这种方式考虑到模块化是不好的,所以我想创建另一个源文件来单独管理class "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来说,class "DEVICE_s"是不可见的(不是完整类型)。
我该如何解决这个问题?谢谢
这是我通常做的事情:
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);
...
}
使用这种方法,用户有责任在使用前分配内存并调用初始化函数(=构造函数)来初始化对象。
它并没有真正给你封装,而是给了最大的分配自由度。为了使封装工作良好,它需要语言的支持。因为 C 是一开始就非常有限的语言,我不建议仅仅为了满足编程范式而添加更多限制。
你想要的是
的不透明类型
- 设备
- DEVICE_SET
这对两者来说都是直接相同的方式:
header,定义
- object 结构的类型不完整。指向它的指针是不透明类型,用于处理 object 的实例并传递给其接口函数
- 接口函数的原型
实施
- 类型齐全
- 接口函数
headers
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;
}
我创建了两个 classes "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;
因为我将这两个 class 放在同一个文件中,所有操作变量 "Instance" 和 "Objects" 的函数都放在这个文件中。
我认为这种方式考虑到模块化是不好的,所以我想创建另一个源文件来单独管理class "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来说,class "DEVICE_s"是不可见的(不是完整类型)。
我该如何解决这个问题?谢谢
这是我通常做的事情:
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);
...
}
使用这种方法,用户有责任在使用前分配内存并调用初始化函数(=构造函数)来初始化对象。
它并没有真正给你封装,而是给了最大的分配自由度。为了使封装工作良好,它需要语言的支持。因为 C 是一开始就非常有限的语言,我不建议仅仅为了满足编程范式而添加更多限制。
你想要的是
的不透明类型- 设备
- DEVICE_SET
这对两者来说都是直接相同的方式:
header,定义
- object 结构的类型不完整。指向它的指针是不透明类型,用于处理 object 的实例并传递给其接口函数
- 接口函数的原型
实施
- 类型齐全
- 接口函数
headers
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;
}