从C代码调用C++方法

5

我已经阅读了这篇文章,它解释了如何从纯C代码调用基于C++的函数。

以下示例最能说明该方法:

// C++ code:
class C {
    // ...
    virtual double f(int);
};
extern "C" double call_C_f(C* p, int i) // wrapper function
{
    return p->f(i);
}

/* C code: */
double call_C_f(struct C* p, int i);
void ccc(struct C* p, int i)
{
    double d = call_C_f(p,i);
    /* ... */
}

然而,我不明白在哪里定义了由'p'指向的实例。请注意,在C代码中,它被传递为指向不透明结构体的指针,在C++代码中,它被认为是指向有效的class C实例的指针,但我没有看到这个指针被初始化的地方。

p.s. 当然,每个与不同语言相关的代码块都使用适当的编译器进行编译,并创建不同的目标文件。

3个回答

6
你需要类似的包装方法来创建和销毁C++对象。
C++代码:
extern "C" C * create_c()
{
    return new C;
}

extern "C" void destroy_c(C *p)
{
    delete p;
}

C语言代码:

// forward declarations (better to put those in a header file)
struct C;
struct C * create_c();
double call_C_f(struct C* p, int i);
void destroy_c(struct C *p);

struct C * p = create_c();
double result = call_C_f(p, i);
destroy_c(p);
p = NULL;

这个答案的一个不错的附加部分可以是关于POD类型的一段,因为C类拥有虚成员函数(使其无法成为POD)是需要不透明结构的真正原因。 - Margaret Bloom
感谢您的帮助。但在使用部分,我不是应该在调用之前需要有函数定义吗?定义来自类型“C * create_c()”...但是C部分无法识别类C。 - Zohar81
2
@Zohar81 只需添加 struct C; 来声明它。 - Bryan Chen
@Bryan - 可能需要强调的是,C 代码可以看到声明,但不应该看到 struct C 的定义 - 只有 C++ 代码应该看到。 - Peter

3
在您的示例中,p 是您的类 C 的一个对象。您需要在 C++ 代码中创建它,然后将其传递给 C。
您还应该在 C 中将指向 C++ 类的指针声明为 void *。类型是未知的,struct C 暗示着它是一个已知的结构体,这是错误的。
示例:
extern "C" {
struct C;
struct C *create_c(void)
{
     return new C;
}

void destroy_c(struct C *ptr)
{
    delete ((C*)ptr);
}
}

1
@BryanChen 它确实可以工作,这不是问题。它只是给人错误的印象,即您实际上知道 C 代码中的类型。但事实并非如此。它是一种您不知道的不透明类型,因此语义是错误的,而 void * 具有正确的语义。 - Leandros
1
@jdarthenay 无论如何你都不会得到警告,void *struct C*是相等的。C不是C++。 - Leandros
是的,我的错误。在大多数现代编译器上,不兼容的指针类型将会发出警告,我忘记了这一点。 - Leandros
C语言没有类型安全性。你的C编译器可能会发出警告,但不一定。而且没有办法教C语言实现类型安全。我的前面的例子在C语言中编译得很好,没有任何警告。但在C++中就不行了。 - Leandros
是的,我在这里同意你。如果我听起来粗鲁,我道歉。 - Leandros
显示剩余6条评论

0

你可以使用C++来创建它,最有可能是使用new C()。在C语言中没有可移植的方法来创建它,所以如果C代码必须能够构造新实例,则必须编写一个extern "C" C* construct_C(); 工厂函数;同样需要为析构函数编写。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接