为什么C ++中的非POD类型对C客户端不透明?

时间:2011-01-11 02:41:24

标签: c++ c

gcc 4.4.4 c89

我刚刚阅读a discussion at DevX关于从C调用C ++代码,因为我必须做类似的事情。我只是想知道“make sure that non POD types in C++ are opaque to C clients.

的用户Vijayan是什么意思

非常感谢任何建议,

5 个答案:

答案 0 :(得分:3)

C只能处理POD类型。

因此,您无法将非POD类型的对象传递给C程序(按值)。此外,如果将非POD类型的指针传递给C程序,它们也无法与指向的对象进行交互。

答案 1 :(得分:3)

POD =普通旧数据结构= C结构,没有虚拟方法等。您需要为C编写包装函数以访问非POD类型(即类)。

有关POD的更多信息: http://en.wikipedia.org/wiki/Plain_old_data_structure

答案 2 :(得分:2)

对于不透明的类型意味着你无法查看它内部:它是一个“黑盒子”,可以传递但不会被C代码直接检查或操作。您通常使用堆分配的内存和void * s来引用对象,或者使用函数来确定必要的长度和缓冲区。

例如,C ++对象可能包含std::string,但是在C ++标准中未指定std::string的布局,因此您无法编写直接读取或写入的C代码到字符串(至少,完全不了解std::string布局,每次更新编译器/ STL时手动重新验证)。

因此,要允许C代码访问该对象,您可以编写C-callable函数,例如:

#if __cplusplus
extern "C" {
#endif
void*       object_new();
const char* object_get_string(void* p_object);
void        object_set_string(void* p_object, const char* s);
void        object_delete();
#if _cplusplus
}
#endif

使用C ++实现ala:

class Object { std::string string_; ... }
void* object_new() { return new Object; }
const char* object_get_string(void* p) { return ((Object*)p)->string_.c_str()); }
...

这里,object_XXX函数为C代码提供了一种使用Object的安全方法。

答案 3 :(得分:2)

使类型不透明意味着,根据链接中的行:

typedef struct base base ; /* opaque */

使句柄的名称可用于C代码,但不是类型的定义。这意味着C代码不能直接访问任何成员,但必须通过接口函数。

请注意,您不必对通用(即void *)指针进行强制转换,但根据9dan的回答,这样做是一种选择。

请注意,即使在纯C代码中,这样的界面风格也是管理封装的一种非常好的方式,就像在标准C流库中一样。

答案 4 :(得分:1)

使客户变得不透明意味着没什么特别的。 C流文件I / O(FILE* f = fopen)API是向客户端提供不透明句柄的典型示例。

显然C无法处理非POD类型,因此您必须从C客户端隐藏C ++实现,但提供访问方法。

示例:

C ++实施

class MyLibrary {
MyLibrary();
~MyLibrary();
int DoSomething();
...
}

C客户声明

typedef void* OPAQUEHANDLE;

extern OPAQUEHANDLE MyLibrary_OpenLibrary();
extern void MyLibrary_CloseLibrary(OPAQUEHANDLE h);
extern int MyLibrary_DoSometing(OPAQUEHANDLE h);

C客户端的实现(在.cpp文件中)

extern OPAQUEHANDLE MyLibrary_OpenLibrary()
{
    return new MyLibrary;
}

extern void MyLibrary_CloseLibrary(OPAQUEHANDLE h)
{
    delete (MyLibrary*) h;
}

extern int MyLibrary_DoSometing(OPAQUEHANDLE h)
{
    return ((MyLibrary*)h)->DoSomething();
}