Скрытие членов в структуре C - PullRequest
57 голосов
/ 20 апреля 2010

Я читал об ООП в C, но мне никогда не нравилось, что у вас не может быть личных данных, как в 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;
}

Отсюда вы можете просто привести одну структуру к другой. Это считается плохой практикой? Или это часто делается?

Ответы [ 13 ]

0 голосов
/ 03 апреля 2014

Связано, но не совсем скрыто.

Это условно осуждает членов.

Обратите внимание, что это работает для GCC / Clang, но MSVC и другие компиляторы тоже могут устареть, так что можно придумать более портативную версию.

Если вы создаете с довольно строгими предупреждениями или предупреждениями как ошибками, это по крайней мере позволяет избежать случайного использования.

// =========================================
// in somestruct.h

#ifdef _IS_SOMESTRUCT_C
#  if defined(__GNUC__)
#    define HIDE_MEMBER __attribute__((deprecated))
#  else
#    define HIDE_MEMBER  /* no hiding! */
#  endif
#else
#  define HIDE_MEMBER
#endif

typedef struct {
  int _public_member;
  int _private_member  HIDE_MEMBER;
} SomeStruct;

#undef HIDE_MEMBER


// =========================================
// in somestruct.c
#define _IS_SOMESTRUCT_C
#include "somestruct.h"

SomeStruct *SomeStruct_Create()
{
  SomeStructSource *p = (SomeStructSource *)malloc(sizeof(SomeStructSource));
  p->_private_member = 42;
  return (SomeStruct *)p;
}
0 голосов
/ 10 октября 2013

Мое решение состояло бы в том, чтобы предоставить только прототип внутренней структуры, а затем объявить определение в файле .c. Очень полезно, чтобы показать интерфейс C и использовать C ++ позади.

.h:

struct internal;

struct foo {
   int public_field;
   struct internal *_internal;
};

.c:

struct internal {
    int private_field; // could be a C++ class
};

Примечание. В этом случае переменная должна быть указателем, поскольку компилятор не может узнать размер внутренней структуры.

0 голосов
/ 20 апреля 2010

Не очень приватно, учитывая, что код вызова может привести к (SomeStructSource *). Кроме того, что происходит, когда вы хотите добавить другого публичного участника? Вам придется нарушить бинарную совместимость.

РЕДАКТИРОВАТЬ: я пропустил, что это было в файле .c, но на самом деле ничто не мешает клиенту скопировать его, или, возможно, даже #include непосредственно в файл .c.

...