I have a class that I want to share between C and C++, where C is only able to get it as a pointer. However because it is an inner class it cannot be forward-declared. Instead this is what our current code does in a common header file:
#ifdef __cplusplus
class Container {
public:
class Object {
public:
int x;
};
};
typedef Container::Object * PObject;
#else
typedef void* PObject;
#endif
This looks like it violates the one definition rule (ODR), because C and C++ see different definition using the #ifdef
. But because this is a pointer, I'm not sure if this creates a real problem or not.
C only uses the pointer in order to pass it to C++ functions, it doesn't directly do anything with it. For instance this code in the common header file:
#ifdef __cplusplus
extern "C" {
#endif
int object_GetX(PObject pObject);
#ifdef __cplusplus
}
#endif /* __cplusplus */
This as how we implemented it in the C++ file:
int object_GetX(PObject pObject) {
return pObject->x;
}
My questions are:
First of all, type-aliasing pointers is usually a recipe for trouble.
Don't do it.
Second, the "inner" class is an overused concept, so my first reflex would be to consider whether it's really necessary.
If it is necessary, you can define an opaque empty type and derive from it for some type safety:
In a shared header:
struct OpaqueObject;
#ifdef __cplusplus
extern "C" {
#endif
int object_GetX(OpaqueObject* pObject);
#ifdef __cplusplus
}
#endif /* __cplusplus */
In a C++ header:
struct OpaqueObject {};
class Container {
public:
class Object : public OpaqueObject {
public:
int x;
};
};
Implementation:
int object_GetX(OpaqueObject* pObject) {
return static_cast<Container::Object*>(pObject)->x;
}