Hướng dẫn accessing c++ classes from c - truy cập các lớp C++ từ c

Tệp tiêu đề của bạn, được chia sẻ giữa mã C và C ++ của bạn:

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

Sau đó, tệp nguồn của bạn:

#include "some_foo.h"

int some_class::some_method(float f)
{
    return static_cast(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);
}

Bây giờ biên dịch nguồn đó và liên kết với nó. Nguồn C của bạn sẽ giống như:

#include "some_class.h"

some_class* myInstance = some_class_new();

int i = some_class_some_method(myInstance, 10.0f);

some_class_delete(myInstance);

Nếu bạn nghiêm túc về việc trộn C và C ++, bạn sẽ muốn Macro.


Dưới đây là một số mẫu Macro sẽ giúp điều này dễ dàng hơn nhiều:

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

Và như thế. Tiêu đề/nguồn của chúng tôi trở thành:

// 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(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);

Và điều đó ngắn gọn hơn nhiều. Nó có thể được thực hiện đơn giản hơn (có thể) với Variadic Macro, nhưng đó là không chuẩn và tôi để nó cho bạn. :] Ngoài ra, bạn có thể tạo Macro cho các chức năng không phải thành viên bình thường.


Lưu ý rằng C không biết tài liệu tham khảo là gì. Nếu bạn muốn liên kết với một tài liệu tham khảo, đặt cược tốt nhất của bạn có lẽ chỉ là viết định nghĩa xuất theo cách thủ công. (Nhưng tôi sẽ nghĩ về nó, có lẽ chúng ta có thể tự động lấy nó).

Hãy tưởng tượng some_class của chúng tôi đã lấy float bằng cách tham chiếu (không phải con quay) (vì bất kỳ lý do gì). Chúng tôi sẽ xác định chức năng như vậy:

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

Và chúng tôi đi. C sẽ giao diện với các tài liệu tham khảo với con trỏ thay thế:

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

Và chúng tôi vượt qua f "bằng cách tham khảo".

Làm cách nào để gọi mã C từ C ++?

Chỉ cần khai báo hàm C ++ bên ngoài "C" (trong mã C ++ của bạn) và gọi nó (từ mã C hoặc C ++ của bạn). Ví dụ: // mã C ++: OXTERN "C" void f (int) ;..
/ * C mã: */.
Double call_c_f (struct c* p, int i) ;.
void ccc (struct c* p, int i).
Double d = call_c_f (p, i) ;.
/ * ... */.

Tôi có thể sử dụng các thư viện C trong C ++ không?

Nhà phát triển Oracle Studio C và C ++, các trình biên dịch sử dụng các tiêu đề tương thích và sử dụng cùng một thư viện thời gian chạy C.Chúng hoàn toàn tương thích.. They are fully compatible.

Tôi có thể trộn mã C và C ++ không?

C và C ++ là hai ngôn ngữ lập trình liên quan chặt chẽ.Do đó, có thể không gây ngạc nhiên cho bạn rằng bạn thực sự có thể trộn mã C và C ++ trong một chương trình.Tuy nhiên, điều này không tự động đến khi bạn viết mã của mình theo cách bình thường.

Extern C được sử dụng để làm gì?

"C" bên ngoài chỉ định rằng hàm được xác định ở nơi khác và sử dụng quy ước gọi ngôn ngữ C.Công cụ sửa đổi "C" bên ngoài cũng có thể được áp dụng cho nhiều khai báo chức năng trong một khối.Trong một khai báo mẫu, Extern chỉ định rằng mẫu đã được khởi tạo ở nơi khác.specifies that the function is defined elsewhere and uses the C-language calling convention. The extern "C" modifier may also be applied to multiple function declarations in a block. In a template declaration, extern specifies that the template has already been instantiated elsewhere.