将结构划分为私有部分和公共部分?
在 C++ 和 Java 中,数据结构可以具有私有
、公共
和受保护
区域。我想将这个概念移植到我正在编写的 C 语言程序中。
在 C 结构体中是否有实现私有或受保护函数指针和数据字段的习惯用法? 我知道 C struct
是公共的,我正在寻找一种习惯用法来帮助隐藏一些实现细节并强制用户使用公共接口。
注意:该语言已由商店选择,因此我一直在将面向对象的概念实施到 C 中。
谢谢。
In C++ and Java, data structures can have private
, public
and protected
regions. I'd like to port this concept to a C language program I am writing.
Are there any idioms for implementing private or protected function pointers and data fields in a C struct
?
I know that C struct
s are public, I'm looking for an idiom to help hide some implementation details and force users to use the public interface.
Note: The language has been chosen by the shop, so I am stuck implementing Object Oriented concepts into C.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如您所知,您不能这样做。然而,有一些习语可以达到类似的效果。
C 将允许您做一些类似于面向对象设计中所谓的“pimpl”惯用法的事情。您的结构可以有一个不透明的指针,指向另一个向前声明的结构,该结构充当该结构的私有数据。对结构进行操作的函数代替成员函数,可以拥有私有成员的完整定义,并且可以使用它,而代码的其他部分则不能。例如:
在标头中,foo.h:
在实现中,foo.c:
在程序中:
请注意,需要使用“构造函数”函数以便为私有数据分配内存。显然,您需要将其与特殊的“析构函数”函数配对,以便正确地释放私有数据。
或者,如果您希望您的结构没有任何公共字段,您可以使整个结构不透明,并且只需让标头类似于
struct Foo的实际定义
在 foo.c 中,并且 getter 和 setter 函数可用于您想要提供直接访问的任何属性。As you know, you cannot do this. However, there are idioms that will allow a similar effect.
C will allow you do do something similar to what is known as the "pimpl" idiom in object-oriented design. Your struct can have an opaque pointer to another forward-declared struct that acts as the struct's private data. Functions that operate on the struct, taking the place of member functions, can have the full definition for the private member, and can make use of it, while other parts of the code cannot. For example:
In a header, foo.h:
In the implementation, foo.c:
In a program:
Note the need to use a "constructor" function in order to allocate memory for the private data. Obviously you would need to pair this with a special "destructor" function in order to deallocate the private data properly.
Or, alternatively, if you would like your struct to have no public fields whatsoever, you could make the entire struct opaque, and just have the header be something like
With the actual definition of
struct Foo
in foo.c, and getter and setter functions available for any properties you would like to provide direct access to.C 中有时使用的概念是:
这使用了标准技巧,即指向结构的指针可以与指向结构中第一个元素的指针互换。
如果您希望所有字段都是私有的,那就更简单了:
#include
lib2.h 的文件不会抱怨,因为我们只使用struct AllPrivate *
,并且所有指针的大小相同,因此编译器不需要了解struct AllPrivate
的内部结构。要创建受保护区域,您只需定义
然后只需确保
dev/include
不被传递即可。The concept sometimes used in C is
This uses the standard trick that a pointer to a struct can be interchanged with a pointer to the first element in a struct.
If you want all your fields to be private, it's even easier:
Files that
#include
lib2.h won't complain, since we only usestruct AllPrivate *
, and all pointers are the same size, so the compiler doesn't need to know the innards ofstruct AllPrivate
.To do a protected region, you'd just have to define
Then it's just a matter of making sure that
dev/include
isn't passed around.对于数据字段——只是不要使用它们。你可以采取一些技巧,比如给它们起一些疯狂的名字来阻止它们的使用,但这并不能阻止人们。唯一真正的方法是创建另一个私有结构,库函数可以通过 void 指针访问该结构。
对于私有函数——使用文件静态函数。将所有库函数放入一个 C 文件中,并将要设为私有的库函数声明为
static
,并且不要将它们放入任何头文件中。For data fields -- just don't use them. You can do some tricks like giving them crazy names to discourage their use, but that won't stop people. The only real way to do it is to make another private struct that is accessed by a void pointer by your library functions.
For private functions -- use file
static
functions. Put all of your library functions in one C file and declare the ones that you want to be private asstatic
and don't put them in any header files.通常按照约定,私有成员的名称中会有一个额外的下划线,或者附加类似
_pri
的内容。或者可能是一条评论。这项技术不会进行编译器强制检查以确保没有人不当访问这些字段,而是向任何阅读 struct 声明的人发出警告,表明内容是实现细节,他们不应该偷看或者戳他们。另一种常见的技术是将结构公开为不完整类型。例如,在您的头文件中,您可能具有:
在实现中,或者库的使用者无法访问的某些内部头文件中,您具有:
您还可以使用 void 指针执行类似的技巧,将其强制转换为右侧放置在代码的“私有”部分。这种方法失去了一些灵活性(例如,您不能拥有未定义类型的堆栈分配实例),但这可能是可以接受的。
如果您想要混合使用私有和公共成员,则可以执行与上述相同的操作,但将私有结构指针存储为公共结构指针的成员,并在库的公共使用者中保留不完整的结构指针。
尽管如此,这引入了一些间接性,这可能会损害性能。您也可以使用一些(通常不可移植,但适用于合理的编译器)类型双关技巧:
这还假设您无法将这些对象存储在堆栈或静态存储中,或者无法在编译时获取大小时间。
Often by convention, a private member has an extra underscore in its name, or something like
_pri
appended. Or possibly a comment. This technique doesn't do compiler-enforced checking to make sure no one inappropriately accesses those fields, but serves as a warning to anyone reading astruct
declaration that the contents are implementation details and they shouldn't peek or poke at them.Another common technique is to expose your structure as an incomplete type. For example, in your header file, you might have:
And in the implementation, or some internal header which is not accessible to consumers of the library, you have:
You can also do similar tricks with void pointers, that get cast to the right place in the "private" portion of the code. This approach loses some flexibility (you can't have a stack-allocated instance of an undefined type, for example), but that may be acceptable.
If you want to have a mixture of private and public members, you can do the same thing as above, but store the private struct pointer as a member of the public one, and leave it incomplete in public consumers of the library.
Although, this introduces some indirection, which may hurt performance. There are some (generally non-portable, but will work on reasonable compilers) type-punning tricks you can use too:
This also assumes that you can't store these objects on the stack or in static storage, or get the size at compile time.
我为你感到遗憾,因为将不同的 OO 概念混入 C 中通常就像圆孔中的方钉一样。话虽这么说,
GObject
支持公共和私有成员,但它是我最不喜欢的体系结构之一。如果您不关心较小的性能影响,您也许可以采取更简单的解决方案 - 有一个充满私有成员的辅助结构,并有一个从主(公共)结构指向该结构的匿名指针。I feel sorry for you, because mashing different OO concepts into C is often like a square peg in a round hole. That being said,
GObject
has support for public and private members, but it's one of my least favourite architectures on earth. If you're not concerned with the minor performance hit, you may be able to do a simpler solution - have a secondary struct that's filled with private members, and have an anonymous pointer to that struct from the primary (public) struct.