简体   繁体   English

C编程解耦接口与实现结构转发声明

[英]C programming decoupling interface from implementation with struct forward declaration

I am writing a C program and using gcc 4.4.6 to compile. 我正在编写一个C程序并使用gcc 4.4.6进行编译。 I do not want to use a c++ compiler. 我不想使用c ++编译器。

I am implementing a component and I intend to have several instances of this component live and owned by other components at runtime. 我正在实现一个组件,我打算在运行时实时拥有该组件的多个实例并由其他组件拥有。

As a means of decoupling the definition of an interface from its implementation and hide the internal structures and datatypes it uses in that implementation I looked to use a forward struct declaration. 作为一种将接口的定义与其实现分离并隐藏它在该实现中使用的内部结构和数据类型的方法,我希望使用前向结构声明。

Interface file: component.h 接口文件: component.h

struct _hidden_implementation_type;
typedef struct _hidden_implementation_type visible_type_to_clients;

int component_function1(visible_type_to_clients instance);

Implementation file: component.c 实现文件: component.c

struct _hidden_implementation_type
{ 
    int foo;
};

Client file: main.c 客户端文件: main.c

int main(int argc, char** argv)
{
    visible_type_to_clients a;
    return component_function1(a);
}  

How do I make this work? 我该如何工作? What other approach is there to allow multiple component instantiation and provide a decoupling between the public interface and implementation otherwise? 还有什么其他方法可以允许多个组件实例化,并提供公共接口和实现之间的解耦?

You're almost there. 你快到了。 Your interface has to be in terms of pointers to the opaque type: 您的界面必须是指向opaque类型的指针:

struct hidden_implementation_type;
typedef struct hidden_implementation_type visible_type_to_clients;

int component_function1(visible_type_to_clients *instance_type);

and: 和:

int main(void)
{
    visible_type_to_clients *a = 0;
    return component_function1(a);
}

This will at least compile — it won't do anything useful, though. 这至少会编译 - 但它不会做任何有用的事情。 You'd probably need a function such as: 您可能需要一个功能,例如:

visible_type_to_clients *new_visible(void);

to create a value of the type and return a pointer it, and then you can use: 创建一个类型的值并返回一个指针,然后你可以使用:

int main(void)
{
    visible_type_to_clients *a = new_visible();
    return component_function1(a);
}

Basically, the clients won't be able to create structures on the stack (or global structures) of your type because you've not told the compiler how big the type is. 基本上,客户端将无法在您的类型的堆栈(或全局结构)上创建结构,因为您没有告诉编译器类型有多大。 But you can deal in pointers — and typed pointers are vastly safer than 'untyped' void * pointers. 但你可以处理指针 - 而且键入的指针比'untyped'void void *指针更安全。

I left out error checking for simplicity. 为简单起见,我省略了错误检查。 I redid the structure tag name without the leading underscore because for all practical purposes, names starting with an underscore are reserved for the implementation . 我在没有前导下划线的情况下重新构造了结构标记名称,因为出于所有实际目的,以下划线开头的名称是为实现保留的 I'd go with: 我会去:

typedef struct VisibleType VisibleType;

where the tag and the type name are the same. 标签和类型名称相同。

Having structs hidden has advantages and disadvantages. 隐藏结构有其优点和缺点。 A hidden struct can never be allocated by the client without constructor. 如果没有构造函数,客户端永远不会分配隐藏的结构。 A hidden struct requires a destructor and the client is required to remember calling it. 隐藏的结构需要析构函数,客户端需要记住调用它。 This is an advantage or a disadvantage depending on your requirement. 根据您的要求,这是一个优点或缺点。

Here are two implementations for comparison: 以下是两个比较实现:

#include <stdio.h>
#include <stdlib.h>

/*VIVIBLE.h*/
typedef struct
{
    int number;
}VISIBLE;
void VISIBLE_INIT(VISIBLE * me, int num);
void VISIBLE_PRINT(const VISIBLE * me);

/*VIVIBLE.c*/
void VISIBLE_INIT(VISIBLE * me, int num) { if(me) me->number = num; }
void VISIBLE_PRINT(const VISIBLE * me) { if(me) printf("%i\n", me->number); }

/*SECRET.h*/
struct CLIENT;
void CLIENT_CTOR(struct CLIENT ** me, int num);
void CLIENT_DTOR(struct CLIENT ** me);
void CLIENT_PRINT(const struct CLIENT * me);

/*SECRET.c*/
typedef struct CLIENT
{
    int number;
}CLIENT;
void CLIENT_CTOR(CLIENT ** me, int num)
{
    if (me)
    {
        *me = (CLIENT*)malloc(sizeof(CLIENT));
        (*me)->number = num;
    }
}
void CLIENT_DTOR(CLIENT ** me)
{
    if (me && *me) free(*me);
    *me = 0;
}
void CLIENT_PRINT(const CLIENT * me) { if(me) printf("%i\n", me->number); }

/*main.c*/
void visible()
{
    VISIBLE vis; // client can allocate memory
    VISIBLE_INIT(&vis, 4);
    VISIBLE_PRINT(&vis);
    //if there is no need for a destructor the client does not need to call one
}

void hidden()
{
    CLIENT * hidden; 
    CLIENT_CTOR(&hidden, 3);
    CLIENT_PRINT(hidden);
    CLIENT_DTOR(&hidden); //Client is never allowed to forget the destructor
}

int main()
{
    visible();
    hidden();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM