所以我读过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*);
它非常冗长,如果我必须添加新的通道类型,我还必须在界面中添加新功能。
我遗失了某种中间立场吗? - 像一个单一的功能,但不是无效*?
答案 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);