C++ 使用C++;来自C的对象

C++ 使用C++;来自C的对象,c++,c,object,C++,C,Object,我想使用C/C++混合代码。我还需要从C代码访问C++对象成员变量。 它工作(至少在gcc中),我将指针传递到对象,并将其作为结构处理 从C++开始: class MyData { ... }; 从C: struct MyData { ... }; (当然,我不会在最终的头文件中重复代码) 1,我不确定使用任何编译器都可以做到这一点。我有什么理由不相信这一点吗 2,如果MyData类具有虚拟成员函数,这将不起作用,但是指向第一个成员变量的指针可以解决问题。这是安全的,还是会给我带来麻

我想使用C/C++混合代码。我还需要从C代码访问C++对象成员变量。 它工作(至少在gcc中),我将指针传递到对象,并将其作为
结构处理

从C++开始:

class MyData {
  ...
};
从C:

struct MyData {
  ...
};
(当然,我不会在最终的头文件中重复代码)

1,我不确定使用任何编译器都可以做到这一点。我有什么理由不相信这一点吗


2,如果
MyData
类具有虚拟成员函数,这将不起作用,但是指向第一个成员变量的指针可以解决问题。这是安全的,还是会给我带来麻烦?

编写一个在C和C++中都合法的类:

struct MyData {
    int member;
};
您可以在两种语言中使用这个类/结构定义,并来回传递它的实例


如果类具有C++函数,如成员函数、基函数、非平凡成员等,那么只能在不透明指针中使用C,这将不允许你访问成员。

编写C和C++中都合法的类:

struct MyData {
    int member;
};
您可以在两种语言中使用这个类/结构定义,并来回传递它的实例


如果类具有C++函数,如成员函数、基函数、非平凡成员等,那么只能在不透明指针中使用C,这将不允许你访问成员。

< P>第一个答案已经被建议定义一个“C”和C++中的合法的“胶类型”。然而,重要的是要强调,这是必要的,但还不够。更精确的答案是,您需要定义具有相同二进制布局的相同类型

澄清:

struct my_struct {
    int a;
    bool b;
};
根据
my_struct
的对齐方式,可以有完全不同的二进制表示形式(当对齐方式为16位和32位时,
my_struct
大小是多少?)。在这种情况下,不仅成员很重要,而且成员之间的内容也很重要,即填充位

这就是为什么指向第一个成员的指针不足以拥有可移植代码的原因


最可移植的方法是定义一个更高级别的API,提取您正在做的事情的本质,并拥有可以通过简单类型(即int、chars、float)参数化的函数 澄清:

struct my_struct {
    int a;
    bool b;
};
根据
my_struct
的对齐方式,可以有完全不同的二进制表示形式(当对齐方式为16位和32位时,
my_struct
大小是多少?)。在这种情况下,不仅成员很重要,而且成员之间的内容也很重要,即填充位

这就是为什么指向第一个成员的指针不足以拥有可移植代码的原因


最可移植的方法是定义一个更高级别的API,提取您正在做的事情的本质,并拥有可以通过简单类型(即int、chars、float)参数化的函数

>经典的方法是,C++代码公开了C类函数来访问类的实例。并将这些函数标记为
外部“C”

示例
mydata.h

#ifndef HEADER_H
#define HEADER_H

#ifdef __cplusplus

class MyData
{
public:
    MyData();
    void SetX(int val);
    int GetX();
private:
    int _x;
};

#endif

typedef void* MYDATA;


#ifdef __cplusplus
extern "C" {
#endif
    MYDATA MyData_new();
    void MyData_delete(MYDATA md);
    void MyData_SetX(MYDATA md, int x);
    int MyData_GetX(MYDATA md);

#ifdef __cplusplus
}
#endif


#endif
然后在
mydata.cpp

#include "mydata.h"

MyData::MyData() : _x(0)
{
}

int MyData::GetX()
{
    return _x;
}

void MyData::SetX(int val)
{
    _x = val;
}

extern "C"  MYDATA MyData_new()
{
    return new MyData();
}

extern "C" void MyData_Delete(MYDATA foo)
{
    auto pFoo = reinterpret_cast<MyData*>(foo);
    delete pFoo;
}

extern "C" void MyData_SetX(MYDATA foo, int x)
{
    auto pFoo = reinterpret_cast<MyData*>(foo);
    pFoo->SetX(x);
}

extern "C" int MyData_GetX(MYDATA foo)
{
    auto pFoo = reinterpret_cast<MyData*>(foo);
    return pFoo->GetX();
}
#包括“mydata.h”
MyData::MyData():x(0)
{
}
int MyData::GetX()
{
返回x;
}
void MyData::SetX(int val)
{
_x=val;
}
extern“C”MYDATA MYDATA_new()
{
返回新的MyData();
}
外部“C”无效MyData_删除(MyData foo)
{
自动pFoo=重新解释铸造(foo);
删除pFoo;
}
外部“C”无效MyData_SetX(MyData foo,int x)
{
自动pFoo=重新解释铸造(foo);
pFoo->SetX(x);
}
外部“C”int MyData_GetX(MyData foo)
{
自动pFoo=重新解释铸造(foo);
返回pFoo->GetX();
}

<>代码>经典的方法是C++代码公开C类函数来访问类的实例。并将这些函数标记为
外部“C”

示例
mydata.h

#ifndef HEADER_H
#define HEADER_H

#ifdef __cplusplus

class MyData
{
public:
    MyData();
    void SetX(int val);
    int GetX();
private:
    int _x;
};

#endif

typedef void* MYDATA;


#ifdef __cplusplus
extern "C" {
#endif
    MYDATA MyData_new();
    void MyData_delete(MYDATA md);
    void MyData_SetX(MYDATA md, int x);
    int MyData_GetX(MYDATA md);

#ifdef __cplusplus
}
#endif


#endif
然后在
mydata.cpp

#include "mydata.h"

MyData::MyData() : _x(0)
{
}

int MyData::GetX()
{
    return _x;
}

void MyData::SetX(int val)
{
    _x = val;
}

extern "C"  MYDATA MyData_new()
{
    return new MyData();
}

extern "C" void MyData_Delete(MYDATA foo)
{
    auto pFoo = reinterpret_cast<MyData*>(foo);
    delete pFoo;
}

extern "C" void MyData_SetX(MYDATA foo, int x)
{
    auto pFoo = reinterpret_cast<MyData*>(foo);
    pFoo->SetX(x);
}

extern "C" int MyData_GetX(MYDATA foo)
{
    auto pFoo = reinterpret_cast<MyData*>(foo);
    return pFoo->GetX();
}
#包括“mydata.h”
MyData::MyData():x(0)
{
}
int MyData::GetX()
{
返回x;
}
void MyData::SetX(int val)
{
_x=val;
}
extern“C”MYDATA MYDATA_new()
{
返回新的MyData();
}
外部“C”无效MyData_删除(MyData foo)
{
自动pFoo=重新解释铸造(foo);
删除pFoo;
}
外部“C”无效MyData_SetX(MyData foo,int x)
{
自动pFoo=重新解释铸造(foo);
pFoo->SetX(x);
}
外部“C”int MyData_GetX(MyData foo)
{
自动pFoo=重新解释铸造(foo);
返回pFoo->GetX();
}

<>这是为C++代码编写一个C接口API。 我将使用一个单独的头文件和一个单独的.cpp文件来实现这一点。在头文件中定义一个API,它强< > < /强>包含C++头。这是新手犯的错误。此标头必须作为代码的C版本独立存在

我不会公开任何类型的
struct
。如果必须,可以使用返回成员指针的函数。然后C代码可以直接读写指针。更好的方法是使用函数显式获取和设置成员值

您可以对对象类型使用
void*
struct
转发声明

然后构建C函数来构造、析构函数、复制和所有成员函数,这些函数将指向
this
的指针作为参数。你不能称之为代码>代码< >代码>,因为这与C++冲突,所以使用<代码>自我>代码>或其他什么。构造函数和复制构造函数显然不接受此
,它们返回指向新对象的指针

将所有这些函数放在带有ifdef保护的
extern“C”{}
块的头中

下面是我玩过的一个例子:



如何做到这一点