简体   繁体   English

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

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

I have a C++ class A having methods while some of them using an instance of another C++ class B as parameter and some are returning an instance of another C++ class C . I have a C++ class A having methods while some of them using an instance of another C++ class B as parameter and some are returning an instance of another C++ class C . How to correctly wrap in C language the class A and all of its methods?如何正确包装 C 语言 class A及其所有方法?

I don't think that my question is a duplicate, since all the existing examples are showing C wrapper (header and source) for a simple C++ class with methods having parameters or return values of simple data type, like int , char* , etc.我不认为我的问题是重复的,因为所有现有示例都显示了 C 包装器(标头和源代码),用于简单的int char*等类型的方法.

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

I know how to write C-language wrapper for class A and its method: using the extern "C" {... } construct.我知道如何为 class A及其方法编写 C 语言包装器:使用extern "C" {... }构造。

But how to do it for classes B and C and their methods?但是对于B类和C及其方法如何做呢?

The generic way is to create a wrapper for each C++ class and a method to generate pointers to those wrappers and another to delete them.通用方法是为每个 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;
}

}

Then you transform each method of each class into a function taking a pointer the struct as the first argument.然后将每个 class 的每个方法转换为 function ,将结构指针作为第一个参数。 A::getValue becomes A::getValue变为

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

Instances can be passed in via pointer, so B::DoSomething becomes实例可以通过指针传入,因此B::DoSomething变为

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

Likewise you can return instances by pointer.同样,您可以通过指针返回实例。 C::SetSomething then becomes C::SetSomething然后变成

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

You will need to be very careful with your memory management in the C code.您需要非常小心 C 代码中的 memory 管理。 See working example here .请参阅此处的工作示例。

I suggest converting struct B and struct C into functions, since they have no members:我建议将struct Bstruct C转换为函数,因为它们没有成员:

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

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

As a reminder, you should prefer to pass structures by pointer in the C language.提醒一下,您应该更喜欢在 C 语言中通过指针传递结构。 Otherwise the compiler will generate copies (except when the compiler can optimize).否则编译器将生成副本(编译器可以优化时除外)。

In almost all cases, you cannot .在几乎所有情况下,您都不能

Only if the struct is a POD, which means that it is a trivial & standard-layout type and that has no non-static members that are non-POD themselves.仅当struct是 POD 时,这意味着它是普通的标准布局类型,并且没有非 POD 本身的非静态成员。

This means, basically, that you can only use structs that are blobs of data without extra behavior and that C "understands" equally as C++.这意味着,基本上,您只能使用没有额外行为的数据块结构,并且 C “理解”与 C++ 一样。

The reason is simple: C has no idea of C++ semantics.原因很简单:C 不知道 C++ 语义。 For instance, if your class has a destructor, who is going to run it?例如,如果你的 class 有一个析构函数,谁来运行它? Or, if your class runs some code when copied, how can C know about it?或者,如果您的 class 在复制时运行了一些代码,那么 C 怎么知道呢?

You have two options:你有两个选择:

  • Share only those types.仅共享这些类型。 If you are unsure whether something is a POD or not, assert it (in C++):如果您不确定某物是否是 POD,请断言它(在 C++ 中):

     static_assert(std::is_pod_v<T>);
  • Keep your classes, but pass opaque pointers to C.保留您的课程,但将不透明的指针传递给 C。 Since you are passing just pointers, C won't do anything with them.由于您只传递指针,因此 C 不会对它们做任何事情。

Note that your example classes B and C are not PODs, so you cannot do it for those.请注意,您的示例类BC不是POD,因此您不能为它们执行此操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM