将结构分区为私有和公共部分?

Tho*_*ews 14 c struct private-methods

在C++和Java,数据结构可以具有private,publicprotected区域.我想将这个概念移植到我正在编写的C语言程序中.

是否有任何习惯用于在C中实现私有或受保护的函数指针和数据字段struct我知道C struct是公开的,我正在寻找一个成语来帮助隐藏一些实现细节并迫使用户使用公共接口.

注意:该商店已选择该语言,因此我无法将面向对象的概念应用到C.

谢谢.

Tyl*_*nry 26

如你所知,你不能这样做.然而,有些习语可以产生类似的效果.

C将允许你做一些类似于面向对象设计中所谓的"pimpl"习语.您的结构可以有一个指向另一个前向声明的结构的不透明指针,该结构充当结构的私有数据.在struct上运行的函数代替了成员函数,可以拥有私有成员的完整定义,并且可以使用它,而代码的其他部分则不能.例如:

在标题中,foo.h:

  struct FooPrivate;

  struct Foo {
     /* public: */
       int x; 
       double y;
     /* private: */
       struct FooPrivate* p;
  };

  extern struct Foo* Foo_Create(); /* "constructor" */

  extern void Foo_DoWhatever(struct Foo* foo); /* "member function" */
Run Code Online (Sandbox Code Playgroud)

在实现中,foo.c:

  struct FooPrivate {
     int z;
  };

  struct Foo* Foo_Create()
  {
     struct Foo* foo = malloc(sizeof(Foo));

     foo->p = malloc(sizeof(FooPrivate));

     foo->x = 0;
     foo->y = 0;
     foo->p->z = 0;

     return foo;
  }

  void Foo_DoWhatever(struct Foo* foo) 
  {
      foo->p->z = 4; /* Can access "private" parts of foo */
  }
Run Code Online (Sandbox Code Playgroud)

在一个程序中:

  #include "foo.h"

  int main()
  {
      struct Foo* foo = Foo_Create();

      foo->x = 100; /* Can access "public" parts of foo */
      foo->p->z = 20; /* Error! FooPrivate is not fully declared here! */

      Foo_DoWhatever(foo); /* Can call "member" function */

      return 0;
  }
Run Code Online (Sandbox Code Playgroud)

请注意,需要使用"构造函数"函数来为私有数据分配内存.显然,您需要将其与特殊的"析构函数"函数配对,以便正确释放私有数据.

或者,或者,如果您希望您的结构没有任何公共字段,您可以使整个结构不透明,并且只需要标题

  struct Foo;

  extern struct Foo* Foo_Create(); /* "constructor" */

  extern void Foo_DoWhatever(struct Foo* foo); /* "member function" */
Run Code Online (Sandbox Code Playgroud)

使用struct Foofoo.c中的实际定义,以及getter和setter函数可用于您希望直接访问的任何属性.

  • 在C99中,您可能需要考虑使用灵活的数组成员`struct FooPrivate p []`替换指向`struct FooPrivate`的指针.这将防止接口的用户意外地制作`struct Foo`的浅拷贝,因为它会使`struct Foo`成为不完整的类型. (4认同)

ram*_*ion 9

有时在C中使用的概念是

// lib.h
typedef struct {
  int publicInt;
  //...
  char * publicStr;
} Public;

Public * getPublic();
int function(Public * public);

// lib.c

typedef struct {
  Public public;
  int privateInt;
  // ...
  char * privateStr
} Private;

static Private * getPrivate();

Public * getPublic() { return (Public*) getPrivate(); }
int function(Public * public) {
  Private * private = (Private *) public;
  // ...
}
Run Code Online (Sandbox Code Playgroud)

这使用标准技巧,指向结构的指针可以与指向结构中第一个元素的指针互换.

如果您希望所有字段都是私有的,则更容易:

// lib2.h
typedef struct AllPrivate * Handle;
Handle getHandle();
int function2(Handle handle);

// lib2.c
struct AllPrivate { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

#includelib2.h不会抱怨的文件,因为我们只使用struct AllPrivate *,并且所有指针的大小都相同,所以编译器不需要知道内部的内容struct AllPrivate.

要做一个受保护的区域,你只需要定义

// include/public.h
struct Public { /* ... */ }
struct Public * getPublic();
int somePublicFunction(struct Public *);

// dev/include/protected.h
struct Protected { struct Public public; /* ... */ }
struct Protected * getProtected();
int someProtectedFunction(struct Protected *);

// dev/src/private.c
struct Private { struct Protected protected; /* ... * /}
struct Public * getPublic() { return (struct Public *) getPrivate(); }
struct Public * getProtected() { return (struct Protected *) getPrivate(); }
int somePublicFunction(struct Public * public) { 
  struct Private private = (struct Private *) public;
  // ...
}
int someProtectedFunction(struct Protected * protected) { 
  struct Private private = (struct Private *) protected;
  // ...
}
Run Code Online (Sandbox Code Playgroud)

然后,这只是确保dev/include不会传递的问题.