如何包装具有参数的 C++ class 方法或在 C 中返回另一个 C++ class 的实例?

How to wrap C++ class method having a parameter or returning an instance of another C++ class in C?

我有一个 C++ class A 有方法,而其中一些使用另一个 C++ class B 的实例作为参数,有些是 returning 另一个 C++ 的实例 class C。如何在 C 语言中正确包装 class A 及其所有方法?

我不认为我的问题是重复的,因为所有现有示例都显示了简单 C++ class 的 C 包装器(header 和源代码),其方法具有参数或 return 简单数据类型的值,如 intchar*

class A {
  public:
    A(int param1);
    int getValue();
  private:
    int value;
}

// method B::DoSomething() has a parameter of type (class) "A"
class B {
  public:
    void DoSomething(A param1);
}

// method C::SetSomething() returns an instance of class "A"
class C {
  public:
    A SetSomething(int value);
}

我知道如何为 class A 编写 C-language 包装器及其方法:使用 extern "C" { ... } 构造。

但是如何为 classes BC 以及他们的方法做到这一点?

我建议将 struct Bstruct C 转换为函数,因为它们没有成员:

void B_DoSomething(A * p_param)
{
  //...
}

A C_SetSomething(int value)
{
  A variable;
  variable.value = value;
  return variable;
}

提醒一下,您应该更喜欢在 C 语言中通过指针传递结构。否则编译器会生成副本(除非编译器可以优化)。

在几乎所有情况下,您不能

仅当 struct 是 POD 时,这意味着它是普通的标准布局类型,并且没有非 POD 本身的非静态成员。

这基本上意味着您只能使用没有额外行为的数据块结构,并且 C "understands" 与 C++ 一样。

原因很简单:C 不了解 C++ 语义。例如,如果您的 class 有一个析构函数,谁来 运行 它?或者,如果您的 class 运行 复制了一些代码,C 如何知道它?

您有两个选择:

  • 只分享那些类型。如果您不确定某物是否是 POD,请断言它(在 C++ 中):

    static_assert(std::is_pod_v<T>);
    
  • 保留你的 classes,但将不透明的指针传递给 C。因为你只是传递指针,C 不会对它们做任何事情。

请注意,您的示例 classes BC 而不是 PODs,因此您不能这样做那些。

通用方法是为每个 C++ 创建一个包装器 class 和一个方法来生成指向这些包装器的指针,另一个方法用于删除它们。

extern "C" {

struct WA{
    void* self;
};

struct WA* new_A( int p1 ){
    WA* wa = new WA;
    wa->self = new A( p1 );
    return wa; 
}

void delete_A( WA* wa ){
    delete static_cast<A*>( wa->self );
    delete wa;
}

}

然后将每个 class 的每个方法转换为一个函数,该函数将结构指针作为第一个参数。 A::getValue 变为

int A_getValue( WA* wa) {
    return static_cast<A*>( wa->self )->getValue();
}

实例可以通过指针传入,所以B::DoSomething变成

void B_DoSomething( WB *wb, WA *param1){
    static_cast<B*>( wb->self )->DoSomething( *static_cast<A*>( param1->self ) );
}

同样,您可以通过指针 return 个实例。 C::SetSomething 然后变成

struct WA* C_SetSomething( WC* wc, int value ){
    A a = static_cast<C*>( wc->self )->SetSomething( value );
    return new_A( a.getValue() );
}

您需要非常小心地管理 C 代码中的内存。请参阅工作示例 here.