优雅地从C调用C++

Car*_*s00 48 c c++ compilation shared-libraries

我们在平原开发了一些项目C(C99).但是,我们有一个库作为源代码(数学库)C++.我们需要这个库,所以我想问一下,集成这些源代码的最优雅方式是什么?

大小之比C,并C++正在20:1使移动C++是不是选项.我们应该使用静态库吗?DLL?(这都是在Windows上).

Mar*_*tos 56

编辑:根据评论中的讨论,我应该指出,将事物分成C兼容struct duck和派生class Duck可能是不必要的.您可以安全地将实施铲除struct duck并消除class Duck,从而避免这种情况real(…).但我不太了解C++(特别是它与C宇宙的交互方式),以便为此提供明确的答案.


没有理由不能简单地将所有C和C++代码链接到一个二进制文件中.

连接到C++代码需要将C++ API包装在C API中.您可以通过extern "C" { ... }在编译C++代码时声明一堆函数,并在编译C客户端代码时不使用extern声明来完成此操作.例如:

#ifdef __cplusplus
extern "C" {
#endif

typedef struct duck duck;

duck* new_duck(int feet);
void delete_duck(duck* d);
void duck_quack(duck* d, float volume);

#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)

您可以在C++源代码中定义duck结构,甚至可以Duck从中继承实数类:

struct duck { };

class Duck : public duck {
public:
    Duck(int feet);
    ~Duck();

    void quack(float volume);
};

inline Duck* real(duck* d) { return static_cast<Duck*>(d); }

duck* new_duck(int feet) { return new Duck(feet); }
void delete_duck(duck* d) { delete real(d); }
void duck_quack(duck* d, float volume) { real(d)->quack(volume); }
Run Code Online (Sandbox Code Playgroud)

  • @Ulterior:不是IMO.如果你把鸭子和青蛙当作无效指针,你可能会不小心让青蛙嘎嘎叫,这会撕裂宇宙的结构. (35认同)
  • @RaffiKhatchadourian:Duck的来源是C++代码,因此必须使用C++编译器进行编译.包含头文件以便使用Duck类的代码可以是C或C++代码,并且这样编译. (2认同)

小智 7

想要从duck结构继承的唯一原因是在C API中暴露一些其属性,无论如何通常认为它是坏的样式.没有继承,你的C头看起来像这样:

struct Duck;

struct Duck* new_Duck(int feet);
void delete_Duck(struct Duck* d);
void Duck_quack(struct Duck* d, float volume);
Run Code Online (Sandbox Code Playgroud)

这将是相应的实现,不需要类型转换:

extern "C" {
#include "Duck.h"
}

class Duck {
public:
    Duck(int feet) : {}
    ~Duck() {}

    void quack(float volume) {}
};

struct Duck* new_Duck(int feet) { return new Duck(feet); }
void delete_Duck(struct Duck* d) { delete d; }
void Duck_quack(struct Duck* d, float volume) { d->quack(volume); }
Run Code Online (Sandbox Code Playgroud)

同样,可以为C++接口(纯虚拟类)及其实现创建C API.在这种情况下,只有构造函数需要基于具体实现(例如new_RubberDuck(2)).析构函数和所有其他函数将自动运行正确的实现,与C++相同.

  • 函数实现也应标记为extern"C".否则会出现链接错误,因为"new_Duck :: i"或您的平台上的任何名称使C++函数与标题的"new_Duck"不匹配. (2认同)

小智 7

C++数学库可以在for实用程序类中实现(仅限静态成员).在这种情况下,可以采取更简单的方法:

class FPMath {
public:
    static double add(double, double);
    static double sub(double, double);
    static double mul(double, double);
    static double div(double, double);
};
Run Code Online (Sandbox Code Playgroud)

然后,C接口的标头将是:

double FPMath_add(double, double);
double FPMath_sub(double, double);
double FPMath_mul(double, double);
double FPMath_div(double, double);
Run Code Online (Sandbox Code Playgroud)

相应的实现可能是:

double FPMath_add(double a, double b) { return FPMath::add(a, b); }
double FPMath_sub(double a, double b) { return FPMath::sub(a, b); }
double FPMath_mul(double a, double b) { return FPMath::mul(a, b); }
double FPMath_div(double a, double b) { return FPMath::div(a, b); }
Run Code Online (Sandbox Code Playgroud)

但也许这说明显而易见......