繁体   English   中英

struct作为基类 - C / C ++互操作性

[英]struct as a base class - C/C++ interoperability

我记得我曾经看到某些代码曾经有一个结构作为基类,而C ++类作为派生类

struct Base_Struct
{

}

class Derived : Base_Struct
{
  ...
}

关键是指向Base_Struct *的指针从C ++文件传递到某些C文件,然后设法使用Base_Struct中的一些函数指针。

我的问题是:如果我将Base_Struct *传递给C文件,C代码是否能够完全使用Base_Struct? 派生类怎么样?

如果我将Base_Struct*传递给C文件,C代码是否能够完全使用Base_Struct

如果它是标准布局类,并且C编译器对C ++编译器等类使用相同的ABI,那么它可以访问所有数据成员。 显然,它无法访问任何成员函数或静态成员,因为这些东西在C中不存在,并且必须被排除在结构的任何C兼容定义之外。

派生类怎么样?

您无法在C程序中定义该类,因此它无法对指针执行任何有趣的操作。

也许它可以用于基类。 但这是非常特殊的情况:

  • POD结构
  • 相同的包装
  • 如果在C和C ++中分配/解除分配,则运行时相同
  • 纯C语法
  • 等等...

但它永远不会直接用于派生类。

但是这会产生很多限制,我会提供一个C级API来分配操作那些在“void *”上定义为别名的指针(我甚至不确定你能在纯C中做这样的别名)。

就像是:

 typedef void* BaseStructPtr;

 BaseStructPtr AllocateBase(/* constructor params */);
 BaseStructPtr AllocateDerived(/* constructor params */);

 TypeOfField1 GetField1(BaseStructPtr ptr);
 TypeOfField2 GetField2(BaseStructPtr ptr);

 /* etc... */

我没有看到从C中声明的结构派生任何问题:

C / C ++

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    int a;
    int b;
} X;

void print(struct StructX* x) {
    printf("%d, %d\n", x->a, x->b);
}

#ifdef __cplusplus
} // extern "C"
#endif

C ++

#include <iostream>

struct Y : StructX {
    int c;

    Y()
    : c(3)
    {
        a = 1;
        b = 2;
    }

    void print() {
        ::print(this);
        std::cout << c << std::endl;
    }
};


int main() {
    Y y;
    y.print();
}

在C ++中声明结构会使事情变得复杂。 现在,结构可能(或将会)具有C不知道的信息,并且(假设)memcpy可能会引入未定义的行为。 要避免这种情况,您必须在C中包装C ++结构的功能:

C / C ++

#ifdef __cplusplus
extern "C" {
#endif

typedef struct Z; // An opaque type (for X) to ensure minimum type safety.

extern int a(Z*);
extern int b(Z*);

#ifdef __cplusplus
} // extern "C"
#endif

C ++

extern "C" {
    int a(Z* z) {
        return ((X*)z)->a;
    }
    int b(Z* z) {
        return ((X*)z)->b;
    }
} // extern "C"

在您的示例中,C编译器将能够使用Base_Struct *指针和访问成员。 您可以在C和CPP文件中使用相同的结构定义而不会出现问题。 只要是为C文件构建结构的Cpp,编译器就可以完成这项工作。

void Give_Typed_Pointer_to_C_Function(Base_Struct* pStruct) {...}
void Give_Pointer_to_C_Function(void* pStruct) {...}
Base_Struct A;
Derived B;
Give_Typed_Pointer_to_C_Function(&A);         // OK
Give_Typed_Pointer_to_C_Function(&B);         // OK 
Give_Pointer_to_C_Function(&A);               // OK    
Give_Pointer_to_C_Function(&B);               // wrong
Give_Pointer_to_C_Function((Base_Struct*)&B); // OK 

为了实现这一点,你必须使用相同的对齐和包装结构,但是当你传递指针时,我认为你是同一个项目所以它应该已经是这样了。

如果你保持struct的顺序相同,你甚至可以做更多

struct S1 { int x; 
            int y;
          };
class C1 {  int x;
            int y;
            int add(int,int); 
          };
void Give_Typed_Pointer_to_C_Function(S1 *pStruct);
C1 object;
Give_Typed_Pointer_to_C_Function((S1*)&object);  // OK

// an safer alternative as you can't have to be sure that S1 and C1 match
struct C1 { int x;
            int y;
#ifdef __cplusplus
            int add(int,int); 
#endif
          };

如果你把Cpp关键字像class / public / private和方法一起放在struct中。 如果你不使用继承,它也会起作用。

暂无
暂无

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

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