问题
I'm writing a small Wrapper API so i can call some C++
code (classes/ functions) from C
.
I got the problem, that one of my C++
functions is initialised in my wrapper header with a "shared_ptr"
.
ClassName *ClassName _new(std::shared_ptr<Lib::Instance> p_Instance);
So as you can see, the wrapper file is infested with C++ style. This is bad because the Wrapper file should be readable by C AND C++
.
This is my Wrapper.h file:
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct ClassName ClassName;
ClassName *ClassName_new(std::shared_ptr<Lib::Instance> p_Instance);
void ClassName_setValue(ClassName* t, double p_value);
void ClassName_delete(ClassName* t);
#ifdef __cplusplus
}
#endif /* __cplusplus */
and this is my Wrapper.cpp file:
#include "Wrapper.h"
#include "ClassName.h"
extern "C"{
ClassName* ClassName_new(std::shared_ptr<Lib::Instance> p_Instance){
return new ClassName(p_Instance);
}
void ClassName_setValue(ClassName* t, double p_value){
t->setValue(p_value);
}
void ClassName_delete(ClassName* t){
delete t;
}
}
And this is the part of my main .cpp file Header:
class ClassName: public Lib::Util::Task {
public:
ClassName(std::shared_ptr<Lib::Instance> p_Instance);
virtual ~ClassName();
void setValue(double p_value);
...
.Cpp:
ClassName::ClassName(std::shared_ptr<Lib::Instance> p_Instance) ...
...
void ClassName::setValue(double p_value){
doSomething()
}
...
I'm not allowed to change my structure of the main c++ file where I am using the ClassName(std::shared_ptr<Lib::Instance> p_Instance);
Do you have any ideas how I can fix this problem? Maybe writing a second Wrapper?
Edit: Here is the error given by the Terminal:
Wrapper.h:21:45: error: expected ‘)’ before ‘:’ token
ClassName *ClassName_new(std::shared_ptr<Lib::Instance> p_Instance);
^
回答1:
The function cannot be used in C, so you can use the pre-processor to remove the declaration just like you used with extern "C"
:
// Wrapper.h
#ifdef __cplusplus
ClassName *ClassName_new(std::shared_ptr<Lib::Instance> p_Instance);
#endif
Although, it this wrapper isn't supposed to be used in C++ by anything other than Wrapper.cpp, then moving the declaration into Wrapper.cpp might be a better option.
If you need a way of invoking ClassName_new
from C, I would suggest steering away from shared pointer. But you could make it work with an opaque wrapper:
// Wrapper.h
struct opaque_wrapper* make_instance(void);
void release_instance(struct opaque_wrapper*);
ClassName *ClassName_new(struct opaque_wrapper*);
// Wrapper.cpp
struct opaque_wrapper {
std::shared_ptr<Lib::Instance> p_Instance;
};
opaque_wrapper* make_instance() {
return new opaque_wrapper{std::make_shared<Lib::Instance>()};
}
void release_instance(struct opaque_wrapper* instance) {
delete instance;
}
ClassName *ClassName_new(struct opaque_wrapper* instance) {
return ClassName_new(instance->p_Instance);
}
回答2:
I would suggest embedding the reference counter into the object and use boost::intrusive_ptr
with it. This way you can pass a plain pointer to C functions and those C functions can still manage the object's lifetime directly calling C-style addref/release
on it.
回答3:
You cannot use classes from C++ in C.
You can define function prototypes of C calling convention C functions, to be used from C++ with the following wrapper code around in the header file:
#ifdef __cplusplus
extern "C" {
#endif
/* put here C calling convention C functions */
#ifdef __cplusplus
};
#endif
and you'll get a definitions file that can be used either in C or in C++. __cplusplus
is a macro defined by the c++ compiler when compiling C++ code, and it introduces the extern "C" {
environment to support C functions. Those functions follow the C style calling conventions (you cannot overload them, you cannot use method definitions or define classes in there)
来源:https://stackoverflow.com/questions/58080505/how-to-wrap-c-stdshared-ptr-in-wrapper-headerfile-so-it-can-be-called-from-c