Mar*_*lon 61 c struct private-members
我一直在读C中的OOP,但我从来不喜欢你不能在C++中拥有像你这样的私人数据成员.但后来我想到你可以创建2个结构.一个在头文件中定义,另一个在源文件中定义.
// =========================================
// in somestruct.h
typedef struct {
int _public_member;
} SomeStruct;
// =========================================
// in somestruct.c
#include "somestruct.h"
typedef struct {
int _public_member;
int _private_member;
} SomeStructSource;
SomeStruct *SomeStruct_Create()
{
SomeStructSource *p = (SomeStructSource *)malloc(sizeof(SomeStructSource));
p->_private_member = 42;
return (SomeStruct *)p;
}
Run Code Online (Sandbox Code Playgroud)
从这里你可以将一个结构投射到另一个结构.这被认为是不好的做法吗?还是经常这样做?
hob*_*bbs 47
sizeof(SomeStruct) != sizeof(SomeStructSource).这将导致有人找到你并有一天谋杀你.
nos*_*nos 36
就个人而言,我更喜欢这样:
typedef struct {
int _public_member;
/*I know you wont listen, but don't ever touch this member.*/
int _private_member;
} SomeStructSource;
Run Code Online (Sandbox Code Playgroud)
毕竟,如果人们想要搞砸了,他们应该被允许 - 不需要隐藏东西,除了:
如果您需要保持ABI/API兼容,那么有两种方法比我看到的更常见.
不要让你的客户端访问struct,给他们一个不透明的句柄(一个带有漂亮名字的void*),为所有东西提供init/destroy和accessor函数.如果您正在编写库,这可确保您无需重新编译客户端即可更改结构.
提供一个不透明的句柄作为你的结构的一部分,你可以随意分配.这种方法甚至在C++中用于提供ABI兼容性.
例如
struct SomeStruct {
int member;
void* internals; //allocate this to your private struct
};
Run Code Online (Sandbox Code Playgroud)
Log*_*ldo 25
你几乎拥有它,但还远远不够.
在标题中:
struct SomeStruct;
typedef struct SomeStruct *SomeThing;
SomeThing create_some_thing();
destroy_some_thing(SomeThing thing);
int get_public_member_some_thing(SomeThing thing);
void set_public_member_some_thing(SomeThing thing, int value);
Run Code Online (Sandbox Code Playgroud)
在.c中:
struct SomeStruct {
int public_member;
int private_member;
};
SomeThing create_some_thing()
{
SomeThing thing = malloc(sizeof(*thing));
thing->public_member = 0;
thing->private_member = 0;
return thing;
}
... etc ...
Run Code Online (Sandbox Code Playgroud)
问题的关键是,这里现在的消费者有没有 SomeStruct的内部的知识,你可以肆无忌惮地改变它,添加和随意删除成员,即使没有消费者无需重新编译.他们也不能"意外地"直接攻击成员,或者在堆栈上分配SomeStruct.这当然也可以被视为一个缺点.
Fel*_*tti 17
我不建议使用公共结构模式.对于C中的OOP,正确的设计模式是提供访问每个数据的功能,从不允许公共访问数据.类数据应该在源处声明,以便是私有的,并以前向方式引用,其中Create和Destroy分配并且没有数据.以这种方式,公共/私人困境将不再存在.
/*********** header.h ***********/
typedef struct sModuleData module_t'
module_t *Module_Create();
void Module_Destroy(module_t *);
/* Only getters and Setters to access data */
void Module_SetSomething(module_t *);
void Module_GetSomething(module_t *);
/*********** source.c ***********/
struct sModuleData {
/* private data */
};
module_t *Module_Create()
{
module_t *inst = (module_t *)malloc(sizeof(struct sModuleData));
/* ... */
return inst;
}
void Module_Destroy(module_t *inst)
{
/* ... */
free(inst);
}
/* Other functions implementation */
Run Code Online (Sandbox Code Playgroud)
另一方面,如果您不想使用Malloc/Free(在某些情况下这可能是不必要的开销),我建议您将结构隐藏在私有文件中.私人会员将是可访问的,但这取决于用户的利益.
/*********** privateTypes.h ***********/
/* All private, non forward, datatypes goes here */
struct sModuleData {
/* private data */
};
/*********** header.h ***********/
#include "privateTypes.h"
typedef struct sModuleData module_t;
void Module_Init(module_t *);
void Module_Deinit(module_t *);
/* Only getters and Setters to access data */
void Module_SetSomething(module_t *);
void Module_GetSomething(module_t *);
/*********** source.c ***********/
void Module_Init(module_t *inst)
{
/* perform initialization on the instance */
}
void Module_Deinit(module_t *inst)
{
/* perform deinitialization on the instance */
}
/*********** main.c ***********/
int main()
{
module_t mod_instance;
module_Init(&mod_instance);
/* and so on */
}
Run Code Online (Sandbox Code Playgroud)
永远不要那样做.如果您的API支持任何需要SomeStruct作为一个参数(我很期待它),那么他们可能会在栈上分配一个,并通过它,你会得到重大失误试图访问私有成员,因为一个编译器为客户端类分配的不包含空间.
在结构中隐藏成员的经典方法是使其成为无效*.它基本上是一个只有你的实现文件知道的句柄/ cookie.几乎每个C库都为私有数据执行此操作.
有时会使用与您提出的方法类似的东西(例如,查看struct sockaddr*BSD套接字API中的不同变量),但在不违反C99的严格别名规则的情况下几乎不可能使用.
但是,您可以安全地执行此操作:
somestruct.h:
struct SomeStructPrivate; /* Opaque type */
typedef struct {
int _public_member;
struct SomeStructPrivate *private;
} SomeStruct;
Run Code Online (Sandbox Code Playgroud)
somestruct.c:
#include "somestruct.h"
struct SomeStructPrivate {
int _member;
};
SomeStruct *SomeStruct_Create()
{
SomeStruct *p = malloc(sizeof *p);
p->private = malloc(sizeof *p->private);
p->private->_member = 0xWHATEVER;
return p;
}
Run Code Online (Sandbox Code Playgroud)