在C中,您可以定义用于保存各种变量的结构;
typedef struct {
float sp;
float K; // interactive form - for display only
float Ti; // values are based in seconds
float Td;
} pid_data_t;
但我们可以说,K
,Ti
和Td
永远不应公开设置,并且只应在操作后用于存储值。所以,我希望这些值不被更新;
pid_data_t = pid_data;
pid_data.K = 10; // no good! changing K should be done via a function
我希望通过函数设置它们;
int8_t pid_set_pid_params(float new_K_dash, float new_Ti_dash,
float new_Td_dash)
{
… // perform lots of things
pid_data->K = new_K_dash;
pid_data->Ti = new_Ti_dash;
pid_data->Td = new_Td_dash;
}
对此有何想法?我知道C ++使用类似于get / set属性,但是想知道人们可能会对C做什么。
答案 0 :(得分:5)
您的公共界面应该只提供不透明指针(可能是DATA*
或data_handle
),以及处理程序函数create_data()
,set_data_value()
,read_data_value()
,free_data()
等,对不透明指针进行操作。
很像FILE*
。
只是不要给你的客户端内部头文件: - )
// library.h
typedef struct data_t * data_handle;
data_handle create_data();
void free_data(data_handle);
私人执行(不发货):
#include "library.h"
struct data_t
{
/* ... */
};
data_handle create_data() { return malloc(sizeof(struct data_t)); }
void free_data(data_handle h) { free(h); }
/* etc. etc. */
答案 1 :(得分:2)
这样做的规范方法是使用不透明指针和公共结构的组合,以及私有元素的分配器,getter和setter。关于这些方面:
foo.h中
typedef struct Foo {
/* public elements */
} Foo;
Foo *new_Foo(void);
void Foo_something_opaque(Foo* foo);
foo.c的
#include "foo.h"
typedef struct Private_Foo_ {
struct Foo foo;
/* private elements */
} Private_Foo_;
Foo *new_Foo(void)
{
Private_Foo_ *foo = malloc(sizeof(Private_Foo_));
/* initialize private and public elements */
return (Foo*) foo;
}
void Foo_something_opaque(Foo *foo)
{
Private_Foo_ *priv_foo = (Private_Foo_*) foo;
/* do something */
}
这是因为C保证结构变量的地址总是等于第一个struct元素的地址。我们可以使用它来创建一个Private_Foo_结构,在开头包含一个公共Foo,给出指向整个事物的指针,编译单元无法访问Private_Foo_ struct定义,只看到一些没有任何上下文的内存。
应该注意的是,C ++在幕后的工作方式非常相似。
正如KereekSB所指出的,如果在数组中使用,这将会中断。
我说:然后不要制作Foo f[]
,不管多么诱人,但要制作一个指向Foo的指针数组:Foo *f[]
。
如果真的坚持在数组中使用它,请执行以下操作:
foo_private.h
typedef struct Private_Foo_ {
/* private elements */
} Private_Foo_;
static size_t Private_Foo_sizeof(void) { return sizeof(Private_Foo_); }
foo_private.h是以某种方式编写的,它可以编译成目标文件。使用一些帮助程序链接它并使用Private_Foo_sizeof()
的结果从一些foo.h.in文件生成实际的,与plattform相关的foo.h。
foo.h中
#include
#define FOO_SIZEOF_PRIVATE_ELEMENTS <generated by preconfigure step>
typedef struct Foo_ {
/* public elements */
char reserved[FOO_SIZEOF_PRIVATE_ELEMENTS];
} Foo;
Foo *new_Foo(void);
void Foo_something_opaque(Foo* foo);
foo.c的
#include "foo.h"
#include "foo_private.h"
Foo *new_Foo(void)
{
Foo *foo = malloc(sizeof(Foo));
/* initialize private and public elements */
return (Foo*) foo;
}
void Foo_something_opaque(Foo *foo)
{
Private_Foo_ *priv_foo = (Private_Foo_*) foo.reserved;
/* do something */
}
恕我直言,这真是一团糟。现在我是智能容器的粉丝(遗憾的是,C没有标准的容器库)。无论如何:在这样的容器中通过像这样的函数创建
Array *array_alloc(size_t sizeofElement, unsigned int elements);
void *array_at(Array *array, unsigned int index);
/* and all the other functions expected of arrays */
请参阅libowfaw以获取此类实现的示例。现在对于Foo类型,提供函数
是微不足道的Array *Foo_array(unsigned int count);
答案 2 :(得分:1)
....
对于OO C这样......
我有pid_data_create(&data) // initializes your struct
和pid_data_set_proportional_gain(&data, 0.1);
等...
所以基本上实现了一个C ++ ish class ...所有带有“class”/“struct”名称的函数的前缀,并始终将struct *作为第一个参数传递。
另外,它应该存储多态性的函数指针,你不应该直接调用那些函数指针,再次,有一个函数将你的struct作为参数,然后可以使函数指针调用(可以检查nulls,伪继承/虚函数和其他东西)
答案 3 :(得分:0)
面向对象是一种思考和建模的方式,数据封装不需要用户直接修改struct数据就可以这样实现:
my_library.h
#ifndef __MY_LIBRARY__
#define __MY_LIBRARY__
typedef void MiObject;
MyObject* newMyObject();
void destroyMyObject(MyObject*)
int setMyObjectProperty1(MyObject*,someDataType1*);
/*Return a pointer to the data/object, classic pass by value */
someDataType1* getMyObjectProperty2Style1(MyObject*);
int setMyObjectProperty2(MyObject*,someDataType2*);
/* The data/object is passed through reference */
int getMyObjectProperty2Style2(MyObject*,someDataType2**);
/* Some more functions here */
#endif
my_library.c
struct _MyHiddenDataType{
int a;
char* b;
..
..
};
MyObject* newMyObject(){
struct _MyHiddenData* newData = (struct _MyHiddenData*)malloc(sizeof(struct _MyHiddenData);
//check null, etc
//initialize data, etc
return (MyObject*)newData;
}
int setMyObjectProperty1(MyObject* object,someDataType1* somedata){
struct _MyHiddenData* data = (struct _MyHiddenData*)object;
//check for nulls, and process somedata
data->somePropery=somedata;
}
someDataType1* getMyObjectProperty2Style1(MyObject*){
struct _MyHiddenData* data = (struct _MyHiddenData*)object;
//check for nulls, and process somedata
return data->someProperty;
}
/* Similar code for the rest */
通过这种方式,您将struct属性封装为私有。以同样的方式,my_libray.c中的静态函数将表现为私有函数。好好看看C,你会发现,你的想象力是你能做的极限。