如何从c文件中调用c ++类及其方法

时间:2010-02-04 20:39:27

标签: c++ c

我正在尝试访问C ++类并从.c文件中调用其方法。

我谷歌这个主题并找到这个http://developers.sun.com/solaris/articles/mixing.html

它说:

  

您可以在C ++中编写extern "C"函数来访问类M对象并从C代码中调用它们。

这是一个用于调用成员函数foo的C ++函数:

extern "C" int call_M_foo(M* m, int i) { return m->foo(i); }

我的问题是我在哪里放线?在我的C ++ .h文件中?或C .h档案?

然后它继续说:

以下是使用类M的C代码示例:

struct M;                       // you can supply only an incomplete declaration

int call_M_foo(struct M*, int); // declare the wrapper function

int f(struct M* p, int j)       // now you can call M::foo
{
  return call_M_foo(p, j);
}

但是我在C文件中如何/在哪里创建类M? 我在哪里放上面的代码? C .h档案? C ++ .h文件?或C .c档案?

谢谢。

感谢 GMan 的详细解答。 我确实按照你的建议。但是我的.c文件中出现了编译错误。

  

main.c中:33:
  ./some_class.h:24:错误:在''标记之前预期'=',',',';','asm'或'属性'   ./some_class.h:25:错误:预期')'在''标记之前   ./some_class.h:26:错误:预期')'在'*'标记

之前

这是我的some_class.h24-26

#ifdef __cplusplus 
class M {

public:
  M();
  virtual ~M(); 

  void method1(char* name, char* msg);
};

extern "C" {
#else
struct M;
#endif

  /* access functions line 24-26 are here*/ 
  M* M_new(void);
  void M_delete(M*);
  void M_method1(M*, char*, char*);
#ifdef __cplusplus 
}
#endif

出于某种原因,我的C编译器不喜欢 GMan 的原始extern "C"中的some_test.h。所以我必须修改到上面。看起来C编译器不喜欢/理解struct M;行。

任何想法都会受到高度赞赏。

5 个答案:

答案 0 :(得分:30)

您的头文件,在C和C ++代码之间共享:

#ifdef __cplusplus // only actually define the class if this is C++

class some_class
{
    public:
        int some_method(float);
};

#else

// C doesn't know about classes, just say it's a struct
typedef struct some_class some_class; 

#endif

// access functions
#ifdef __cplusplus
    #define EXPORT_C extern "C"
#else
    #define EXPORT_C
#endif

EXPORT_C some_class* some_class_new(void);
EXPORT_C void some_class_delete(some_class*);
EXPORT_C int some_class_some_method(some_class*, float);

然后你的源文件:

#include "some_foo.h"

int some_class::some_method(float f)
{
    return static_cast<int>(f);
}

// access functions
EXPORT_C some_class* some_class_new(void)
{
    return new some_class();
}

EXPORT_C void some_class_delete(some_class* this)
{
    delete this;
}

EXPORT_C int some_class_some_method(some_class* this, float f)
{
    return this->some_method(f);
}

现在编译该源,并链接到它。您的C源代码如下:

#include "some_class.h"

some_class* myInstance = some_class_new();

int i = some_class_some_method(myInstance, 10.0f);

some_class_delete(myInstance);

如果你真的想要混合使用C和C ++,你会想要宏。


以下是一些示例宏,可以让这更容易:

// in something like c_export.h
// extern "C" macro
#ifdef __cplusplus
    #define EXPORT_C extern "C"
#else
    #define EXPORT_C
#endif

// new
#define EXPORT_C_CLASS_NEW(classname) EXPORT_C \
            classname * classname##_new(void)

#define EXPORT_C_CLASS_NEW_DEFINE(classname) \
            EXPORT_C_CLASS_NEW(classname) \
            { return new classname (); }

// repeat as much as you want. allows passing parameters to the constructor
#define EXPORT_C_CLASS_NEW_1(classname, param1) EXPORT_C \
            classname * classname##_new( param1 p1)

#define EXPORT_C_CLASS_NEW_1_DEFINE(classname, param1) \
            EXPORT_C_CLASS_NEW_1(classname, param1) \
            { return new classname (p1); }

// delete
#define EXPORT_C_CLASS_DELETE(classname) EXPORT_C \
            void classname##_delete( classname * this)

#define EXPORT_C_CLASS_DELETE_DEFINE(classname) \
            EXPORT_C_CLASS_DELETE(classname) \
            { delete this; }

// functions
#define EXPORT_C_CLASS_METHOD(classname, methodname, ret) EXPORT_C \
            ret classname##_##methodname##( classname * this)

#define EXPORT_C_CLASS_METHOD_DEFINE(classname, methodname, ret) \
            EXPORT_C_CLASS_METHOD(classname, methodname, ret) \
            { return this->##methodname##(); }

// and repeat as necessary.
#define EXPORT_C_CLASS_METHOD_1(classname, methodname, ret, param1) EXPORT_C \
            ret classname##_##methodname( classname * this, param1 p1)

#define EXPORT_C_CLASS_METHOD_1_DEFINE(classname, methodname, ret, param1) \
            EXPORT_C_CLASS_METHOD_1(classname, methodname, ret, param1) \
            { return this->##methodname##(p1); }

等等。我们的标题/来源变为:

// header
#include "c_export.h" // utility macros

#ifdef __cplusplus // only actually define the class if this is C++

class some_class
{
    public:
        int some_method(float);
};

#else

// C doesn't know about classes, just say it's a struct
typedef struct some_class some_class; 

#endif

// access functions
EXPORT_C_CLASS_NEW(some_class);
EXPORT_C_CLASS_DELETE(some_class);
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float);

// source
#include "some_foo.h"

int some_class::some_method(float f)
{
    return static_cast<int>(f);
}

// access functions
EXPORT_C_CLASS_NEW_DEFINE(some_class);
EXPORT_C_CLASS_DELETE_DEFINE(some_class);
EXPORT_C_CLASS_METHOD_1_DEFINE(some_class, some_method, int, float);

这更加简洁。它可以变得更简单(可能)与可变宏,但这是非标准的,我把它留给你。 :]此外,您可以为正常的非成员函数创建宏。


请注意,C 知道哪些引用。如果要绑定到引用,最好的办法可能就是手动编写导出定义。 (但我会考虑一下,也许我们可以自动获得它。)

想象一下,我们some_class采用了float by(非const)引用(无论出于何种原因)。我们这样定义函数:

// header
// pass by pointer!                                     v
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float*) ;

// source
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float*) 
{
    // dereference pointer; now can be used as reference
    return this->some_method(*p1);
}

然后我们走了。 C将使用指针与引用接口:

// c source, if some_method took a reference:
float f = 10.0f;
int i = some_class_some_method(myInstance, &f);

我们通过引用传递f“。

答案 1 :(得分:3)

您需要将其拆分为C ++标头和实现文件。

foo.h中:

extern "C" int call_M_foo(M* m, int i);

foo.cc:

extern "C" int call_M_foo(M* m, int i) {
    return m->foo(i);
}

要创建M类型的对象,您需要一个类似的功能:

foo.h中:

struct M;
extern "C" M* create_M();

foo.cc:

extern "C" M* create_M() {
    return new M;
}

答案 2 :(得分:2)

这里有几个问题,所以我会单独回答。

  

我的问题是我在哪里放线?在我的c ++ .h文件中?还是c .h文件?

extern "C"行进入C ++文件。它基本上告诉编译器 将extern "C"块中的所有内容限制为C ++的C子集,并将其限制为 相应地在此区域中声明的导出函数。

  

但我如何/在哪里创建我的c文件中的类M?

你做不到。 C没有类的概念,绝对没有 直接实例化一个类的方法。你基本上必须导出一个C函数 在您的C ++文件中创建类并将其作为指针返回。那么你 可以在C应用程序周围传递该指针。你实际上无法修改 直接在您的C应用程序中类,因为C不支持类,并且 您的C ++编译器可能会在其中插入“隐藏”变量用于簿记 实际的班级宣言。

  

我在哪里放上面的代码?

使用struct ure指针的代码片段位于C文件中。你是 被迫使用struct指针,因为C根本不支持类。 您可以在C实现中的任何位置使用该函数调用函数调用 文件,就像正常的C函数调用一样。

答案 3 :(得分:1)

您需要的所有信息都在您提供的链接中。您只需要了解C和C ++代码之间需要严格分离。

  1. C ++代码可以调用任何C代码。
  2. C代码通常无法调用任何C ++代码。
  3. C函数可以通过C ++代码实现。
  4. 要理解的关键部分是C和C ++编译器在以不同方式创建目标文件时会破坏函数名称,因此它们通常无法互操作(在链接时),除了可以提示C ++知道使用extern "C"

    的差异

    原型: {C}编译器可能会将void f(int);修改为:_f,但C ++编译器可能会选择一个非常不同的名称,例如f_int,因此链接器不会知道它们应该是相同。

    然而:

    extern "C" void f(int);

    会被C ++编译器损坏到_f,但C编译器会阻塞extern "C"。为了避免这种情况,你应该使用这样的东西:

    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void f(int);
    
    #ifdef __cplusplus
    } /* closing brace for extern "C" */
    #endif
    

    现在整个上述部分可以存在于.h文件中,并且正如sun.com文章所述,是一个混合语言标题。

    这意味着.c或.cpp文件可以#include此标头和代码可以调用f();
    .c或.cpp文件可以#include此标头并实现它:

    void f()
    {
    }
    

    现在好的一点是.cpp文件可以实现它来调用它喜欢的任何C ++代码。

    现在回答您的具体问题:

    1. 第一个代码示例只能放在.cpp文件中。
    2. 第二个代码示例只能放在.c文件中。
    3. 此外,必须仅在C ++文件中声明和定义类M.

答案 4 :(得分:0)

您链接的网站已经有了答案:

  

您可以在a中声明功能打印   由C和。共享的头文件   C ++代码:

#ifdef __cplusplus extern "C"
#endif int print(int i, double d);
  

您最多可以声明一个功能   作为extern“C”的重载集   这是示例的C头   包装函数:

int g_int(int); 
double g_double(double);

基本上,两者之间可以共享一个声明函数原型的头,如果你在C ++中则添加extern“C”修饰符以确保可以在C中的对象中访问该函数。你定义了稍后在C ++代码中的函数,如果有必要在类等中,并且像C一样使用C中的函数。