【问题标题】:How to wrap C++ class method having a parameter or returning an instance of another C++ class in C?如何包装具有参数的 C++ 类方法或在 C 中返回另一个 C++ 类的实例?
【发布时间】:2019-09-24 20:20:52
【问题描述】:

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

我不认为我的问题是重复的,因为所有现有示例都显示了简单 C++ 类的 C 包装器(标题和源代码),其方法具有简单数据类型的参数或返回值,例如 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);
}

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

但是对于 BC 类及其方法如何做呢?

【问题讨论】:

  • C API 首先如何暴露A
  • 如果你有ABC作为结构,然后有一些像void B_DoSomething(struct A *param1)struct A C_SetSomething(int value)这样的函数。这是你想要的吗?
  • C 语言在其结构中没有可访问性(例如 publicprivate)。此外,如果你想在 C 结构中使用函数,则必须使用函数指针。
  • 这是可行的,因为有编译器从C++转换为C。他们使用对象作为参数,例如object.DoSomething(param)变成DoSomething(object, param);,每个方法都根据重命名到它的签名(它的参数和返回值的类型)

标签: c++ c wrapper


【解决方案1】:

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

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;
}

}

然后,您将每个类的每个方法转换为一个函数,该函数将结构指针作为第一个参数。 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 ) );
}

同样,您可以通过指针返回实例。 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

【讨论】:

  • 谢谢@Thomas!这就是我想要的。
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

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

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

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

    原因很简单:C 不知道 C++ 语义。例如,如果你的类有一个析构函数,谁来运行它?或者,如果你的类在复制时运行了一些代码,C 怎么知道呢?

    你有两个选择:

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

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

    请注意,您的示例类 BC 不是 POD,因此您不能为它们这样做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-09-29
      • 1970-01-01
      • 2016-11-26
      • 1970-01-01
      • 1970-01-01
      • 2017-04-30
      • 1970-01-01
      相关资源
      最近更新 更多