C ++库的C包装器 - 继承怎么样?

时间:2014-03-04 11:50:59

标签: c++ c inheritance wrapper

所以我读过Developing C wrapper API for Object-Oriented C++ code,我喜欢这个方法,我用我的库 - 每个相应的C ++类的不透明句柄;避免使用void*

但是现在,我面临着'接口'和基类的思考。例如,我有一个“通道”类的类层次结构 - 一个“通道”的基类和派生的具体类,例如,串行通信,内存缓冲区,套接字等。

所以我有:

typedef struct serial_channel serial_channel;
typedef struct socket_channel socket_channel;
typedef struct memory_channel memory_channel;

serial_channel* create_serial_channel();
socket_channel* create_socket_channel();
memory_channel* create_memory_channel();

但我希望能够将其中任何一个传递给函数以将其与“设备”对象相关联:

void associate_device_with_channel(device*, channel*);

在C ++中很容易,因为它理解基类。我如何在C包装器库中处理此问题 - C中的channel是什么类型?

我唯一能想到的是我必须求助于void *来代表一个基类?

typedef void* channel;
void associate_device_with_channel(device*, channel*);

它有效,但是让我传递任何指针吗?

另一方面,我可以编写一组与派生通道类匹配的函数:

void associate_device_with_serial_channel(device*, serial_channel*);
void associate_device_with_socket_channel(device*, socket_channel*);
void associate_device_with_memory_channel(device*, memory_channel*);

它非常冗长,如果我必须添加新的通道类型,我还必须在界面中添加新功能。

我遗失了某种中间立场吗? - 像一个单一的功能,但不是无效*?

3 个答案:

答案 0 :(得分:3)

没有任何完美的方法。您正在尝试使您的函数使用一些不透明句柄(具有相应基类的句柄)但不使用任何句柄类型(void*将接受) ,C中没有东西。

如果您愿意,可以提供一个函数,该函数需要serial_channel*并返回channel*,另一个函数用于另一个channel子类。这可以让您远离不安全的C语言转换,并且不需要numfuncs*numderivedclasses个不同的channel - 获取功能。

就个人而言,我只是void*。毕竟他们正在使用C ......显然他们并不太关心他们的语言,以保证他们的安全。

答案 1 :(得分:2)

首先,我会建立我的结构:

typedef void base_class;
struct base_class_impl
{
    // base class member variables go here
}
struct derived_class
{
    // base class must come first in the derived struct
    struct base_class_impl base;
    // derived class member variables go here
}

然后,我会指向base_class作为我的函数的参数:

int base_class_get_count(base_class *b);

我总是在函数的开头进行转换:

int base_class_get_count(base_class *b)
{
    struct base_class *base = (struct base_class *)b;
    // Operate on the object now
}

这使base_class_get_count()甚至可以在派生类型的对象上工作。缺点是它不允许派生类型覆盖一个方法 - 你必须更进一步,实现你自己的API调用的函数指针表(如base_class_get_count)调度到,基于在表格中的条目。

答案 2 :(得分:1)

如果您只针对GCC或Clang(我怀疑如果您的目标是Visual Studio,则不会打扰C),您可以选择使用非标准__transparent_union__属性创建一个联合列出函数可以接受的类型。接受带有__transparent_union__属性的union参数的函数将接受该联合或其中包含的任何类型。

union associable_channel
{
    channel* a;
    serial_channel* b;
    socket_channel* c;
    memory_channel* d; 
} __attribute__((__transparent_union__));

void associate_device_with_channel(union associable_channel chan);

serial_channel* serial;
socket_channel* socket;
memory_channel* mem;
associate_device_with_channel(serial);
associate_device_with_channel(socket);
associate_device_with_channel(mem);