我们开发了一些简单的项目C
(C99)。但是,我们在C++
中有一个作为源代码的库(数学库)。我们需要这个库,所以我想问一下,整合这个源代码最优雅的方式是什么?从C中优雅地调用C++
尺寸为C
和C++
之间的比率为20:1
因此不能选择C++
。我们应该使用静态库吗? DLL? (全部在Windows上)。
我们开发了一些简单的项目C
(C99)。但是,我们在C++
中有一个作为源代码的库(数学库)。我们需要这个库,所以我想问一下,整合这个源代码最优雅的方式是什么?从C中优雅地调用C++
尺寸为C
和C++
之间的比率为20:1
因此不能选择C++
。我们应该使用静态库吗? DLL? (全部在Windows上)。
编辑:基于在评论的讨论,我要指出的是分离的东西到C兼容struct duck
和派生class Duck
可能是不必要的。您可能可以安全地将执行铲入struct duck
并消除class Duck
,从而避免real(…)
。但是我不太了解C++(尤其是它与C宇宙交互的方式),以便为此提供明确的答案。
没有理由你不能简单地链接所有的C和C++代码一起到一个单一的二进制文件。
与C++代码的接口需要将C++ API封装到C API中。你可以通过在编译C++代码时在extern "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
你可以在你的C++源定义鸭结构,甚至从它继承了真正的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); }
很好的答案,谢谢! – Cartesius00
国际海事组织空白指针会更适合在这里 – Ulterior
@Ulterior:不IMO。如果你把鸭子和青蛙当成空针,你可能会不小心让青蛙嘎嘎作响,这会撕裂宇宙的结构。 –
的唯一原因想从鸭结构继承会在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);
,这将是相应的实施,而无需类型转换:
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); }
以同样的方式,一个C API可为C++接口(纯虚拟类)及其实现创建。在这种情况下,只有构造函数需要基于具体实现(例如new_RubberDuck(2))。析构函数和所有其他函数将自动在正确的实现上运行,与C++中的一样。
函数实现也应该被标记为extern“C”。否则,你会得到链接错误,因为“new_Duck :: i”或者你的平台上的任何名字使得C++函数与头文件的“new_Duck”不匹配。 – uliwitness
C++数学库很可能在实用程序类(仅限静态成员)中实现。在这种情况下,一个更简单的方法可以采取:
class FPMath {
public:
static double add(double, double);
static double sub(double, double);
static double mul(double, double);
static double div(double, double);
};
针对C接口的头然后将:
double FPMath_add(double, double);
double FPMath_sub(double, double);
double FPMath_mul(double, double);
double FPMath_div(double, double);
和相应的实现可能是:
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); }
但也许这是明显的....
There is一种创建“黑客”的方法,允许您直接调用某些对象的成员函数。
您需要做的第一件事是创建一个extern "C"
工厂函数,该函数返回一个指针(如void*
)到对象。
您需要的第二件事是成员函数的损坏名称。
然后,您可以使用mangled名称并将工厂函数返回的指针作为第一个参数传递给该函数。
注意事项:
当然这不是我推荐的,事实上恰恰相反。我强烈建议不要执行此答案中概述的内容。它不受支持,可能未定义行为,并可能以怪异和不可预知的方式打破。
C++库是否提供了一个合适的C接口(自由函数而不是成员函数,没有例外,extern“C”等)? –
混合C和C++的常见问题解答:http://www.parashift.com/c++-faq/mixing-c-and-cpp.html – Maciej
[如何从C调用C++函数](http:// stackoverflow.com/questions/2744181/how-to-call-c-function-from-c) –