Faking inheritance in C: Will alignment break my neck? - c++

I have a C struct that is used in various C and C++ code (via extern "C").
#ifdef __cplusplus
extern "C" {
#endif
typedef struct A A;
struct A {
/*some members*/
};
#ifdef __cplusplus
}
#endif
Allocation, initialisation and release is done by separate member functions under my control, but I do not control access to members, as they are accessed all over the place.
The trouble is, I cannot change the struct's definition in the header that is heavily used throughout the system, but I still want to extend the type and add some members. Since this must compile as both C++ and C, I cannot simply create a derived type struct B : public A. So my idea was to add this type to the cpp file:
#ifdef __cplusplus
extern "C" {
#endif
typedef struct B B;
struct B {
A parent; // <---- public inheritance
/*some members*/
};
#ifdef __cplusplus
}
#endif
Now, I can modify all functions in the cpp file but I still have to hand out and accept A* outside of the compilation unit as nobody knows what B is.
So, I'm wondering if there is a sane and well-defined way of doing this. Can I simply cast my B*s to A*s and back or would it I have to explicitly convert them:
A* static_cast_A(B* b) {
return &(b->parent);
}
B* static_cast_B(A* a) {
B* const b = 0;
unsigned const ptrdiff = (unsigned)((void*)(&(b->parent)));
return (B*)(((void*)a)-ptrdiff);
}
Are there any more problems with this or should I do it differently altogether?

As long as you don't introduce a virtual table (by adding a virtual method or destructor) in struct B and parent member of that struct is the first element, then it is safe to just case B to A.
Casting A to B is safe, too, but only if the original pointer is actually pointing to B and not to something else, like only A structure itself, obviously.
In case when parent is not the first member of struct B, you would have to use container_of macro as seen in Linux kernel, for example. It works off the member pointer offsets (i.e. some good explanation can be found here).
Also, by default both structs will have the same alignment. I am not sure how the compiler would place A into B if you tweak one of the structs alignment. I guess that is compiler dependent, but should be easy to figure out.
If B has a virtual table, you must know compiler internals to convert the pointers correctly. For example, GCC on x86_64 adds 8 bytes offset thus you have to offset it manually when converting. But that won't work in case of virtual inheritance (virtual base classes), to solve that you have to resort to using RTTI etc... But this is outside of the scope of your question and I'd recommend you don't go that way.
Hope it helps.

Alignment requirements shouldn't cause any problems, and this is indeed the default way to fake inheritance in C.
However, your static_cast_B() is not portable (in particular void * arithmetics and conversion to unsigned in case of sizeof (void *) > sizeof (unsigned) - the latter should still work, but is something of a code smell).
I suggest using the following code instead:
#include <stddef.h>
B* static_cast_B(A* a) {
return (B*)((char*)a - offsetof(B, parent));
}

Related

Circular include dependency/Forward Declarations

All the solutions to circular include dependencies I've seen just say in "this particular case" the full class definition isn't necessary since "you" are only using pointers to that class.
I encountered this problem and fixed it using forward declarations.
I am wondering what are you supposed to do when you need the specific definition of the other class in both classes.
Also, why does using a pointer to the class allow you use a forward declaration instead of a class definition?
In what cases would you need the specification known beforehand for both classes?
One impossible case is the following:
class A
{
B m_b;
};
class B
{
A m_a;
};
But this is impossible since the size of class A depends on the size of class B, but the size of class B depends on the size of class A. You'll also get an infinite series A myA; myA.m_b.m_a.m_b.m_a.... when you try to construct either.
If you use pointers, you don't need to know the size of either; a pointer is always the same size depending on the platform your are on. And the series disappears because objects in the heap need to be created explicitly.
I am wondering what are you supposed to do when you need the specific
definition of the other class in both classes.
It can be done with forward declarations and deferred definitions in modern compilers. Many older compilers only allow pointers & references to forward declared types.
Here's a contrived example:
A.hpp
class B;
class A
{
public:
int32_t Value;
A(int32_t value) : Value(value) { }
int32_t Add(B b) const;
}
B.hpp
#include "A.hpp"
class B
{
public:
int32_t Value;
B(int32_t value) : Value(value) { }
int32_t Sub(A a) const;
}
AB.hpp
#include "A.hpp"
#include "B.hpp"
inline int32_t A::Add(B b) const
{
return this->Value + b.Value;
}
inline int32_t B::Sub(A a) const
{
return this->Value - a.Value;
}
Also, why does using a pointer to the class allow you use a forward
declaration instead of a class definition?
Forward declarations are just names to the compiler. The concept exists so you can use types that haven't been defined yet. This is necessary because of the way C++ parses code, an artifact of the C language it inherits a great deal from. C++ parsers are really just forward-only text processors that inject text when you #include and use macros. It's a conceptually simple model that made C/C++ compilers easier to write in the early days. Contrast this to C#/Java where you just use using/import and happily create circular dependencies between classes with simple syntax.
Pointers are really just integers, similar to short and int, but with special semantics enforced by the language and a fixed size known at compile time based on the CPU architecture. This makes pointer declarations very simple for compilers to deal with.
Forward declaration facilitates circular dependencies and implementation hiding(which also happens to speed up compilation time). Consider the pimpl idiom. Without forward declarations there's no type-safe way to hide implementation details.

c++ typedef access violation while calling pointer

I have this code:
(exe)
#include <Windows.h>
#pragma comment(lib, "user32.lib")
class Dummy;
typedef void(Dummy::*Referece)(int i);
typedef void(*InitCall)(void*, Referece);
class Dummy
{
public:
Dummy(){}
void callMe(int val)
{
MessageBoxA(0, "ok", "ok", 0);
}
};
int main()
{
Dummy* obj = new Dummy();
HMODULE ha= LoadLibraryA("aa.dll");
InitCall val = (InitCall)GetProcAddress(ha, "Init");
val(obj, &Dummy::callMe);
}
and my dll:
(.h)
#pragma once
#define DLL_EXPORT __declspec(dllexport)
class Test;
typedef void (Test::*Reference)(int a);
#ifdef __cplusplus
extern "C"
{
#endif
void DLL_EXPORT Init(Test* Object, Reference reference);
#ifdef __cplusplus
}
#endif
(.cpp)
#include "your.h"
void DLL_EXPORT Init(Test * Object, Reference reference)
{
(Object->*reference)(1);
}
I reproduced the system and should be like this cause i can't change code in one side.
Why i get access violation? Calling "val(obj, ref)" i expect a pointer to class + offset to method call.
A pointer to member is not an "offset into the class." There's no such thing. In some cases (such as a pointer to a virtual member function in a class with a simple inheritance hierarchy), its implementation can consist of such an offset (plus potentially a few other bits of data).
However, for a non-virtual function (like in your example), it likely has a plain pointer to function underneath it. Non-virtual functions are not stored in any "table" with "offsets" (there is at least no reason to store them that way), they're most likely implemented as normal bog-standard functions with a mangled name and a prepended prameter.
Pointers to member are a somewhat tricky part of C++, largely due to the fact that there is no obvious mapping to an implementation concept and different compilers can handle them in different ways. Trusting that a void (Dummy::*)(int) and void (Test::*)(int) are binary compatible is quite fragile.
In general, you cannot expect the binary representation of a pointer to Dummy::callMe to be in any way similar to that of a pointer to a member function of Test, as it can depend too much on the definitions of Dummy and Test, and how the compiler implements pointers to member.
To top it off, the way in which Visual Studio's compiler handles pointers to member by default is non-conforming (so, from most perspectives, broken). This default handling is such that to correctly form a pointer to member of a class, the compiler needs to have seen the definition of the class. The reason is that the most general implementation of a pointer to member is quite large (4 native words, I believe), because it has to account for virtual inheritance and such. The most common case of a single-base class with no virtuals can fit in a native word.
Therefore, if you want to reliably use perfectly standard C++ constructs like accepting a pointer to member of a class whose definition is not visible at the site, you have to use the compilation flag /vmg. With this, the most general representation will always be used.
The default behaviour, /vmb, optimises the binary representation (including size!) of A::* based on the definition of A. It's therefore impossible to create a typedef such as yours with this behaviour in effect.
As to what your options are:
If you absolutely have to pass through a C-style interface, force use of a C-style function as a callback on the side calling the callback, and create a wrapper C-style function on the registering side. Something like this:
class Dummy
{
void callMe(int) {}
};
extern "C" void fw_Dummy_callMe(void *self, int i)
{ static_cast<Dummy*>(self)->callMe(i); }
Plus
#ifdef __cplusplus
extern "C"
{
#endif
void DLL_EXPORT Init(void* Object, void (*reference)(void*, int));
#ifdef __cplusplus
}
#endif
If you can have C++ in the interface (that is, the compiler and version will always be the same on both sides of the DLL interface), you can use a pointer to member function provided that:
The two sides will not see different definitions of the class. It's fine if one of them only has a non-defining declaration, though. To be 100% C++ conformant, the names of the class should be the same.
You use /vmg when building both the DLL and its client.

Static library: hiding private members from header file

I wish to compile part of my code as a static library to include in other project. Of course I'll have to distribute the compiled library and an header file containing the class declaration and the public members, but I don't know if it's possible to move all private members and declarations to a place different than the header file.
Example:
In the project.h file:
class MyClass
{
public:
MyClass();
void Give_me_an_input(int);
int Get_your_output();
private:
int a, b;
int MySecretAlgorithm();
};
In the .cpp file:
MyClass::MyClass()
{
a = 1;
b = 0;
}
void MyClass::Give_me_an_input(int c)
{
b = c;
}
int MyClass::Get_your_output()
{
return MySecretAlgorithm();
}
int MyClass::MySecretAlgorithm()
{
return (a + b);
}
Is there a way to move all private members int a, b; and int MySecretAlgorithm(); to a place different than the header file?
The pointer to implementation idiom can be used in such a scenario, commonly referred to as pimpl.
The basic idea is to take the implementation details out of the declaration
and simply have an opaque pointer to the implementation details.
std::unique_ptr is used in the the following example; but you could of course just use normal pointers.
// my_class declaration unit.
class my_class {
private:
class impl;
unique_ptr<impl> pimpl;
public:
};
// my_class implementation unit
class my_class::impl {
int whatever;
int whenever;
};
my_class::my_class(): pimpl( new impl )
{
}
Over the years I've seen some hacks to do this, but I don't think they are worth it. If your library is reasonably 'chunky' (ie: no method is being called a billion times a microsecond); and you can re-write chunks of your code...
You might consider making all the public stuff an abstract class (all virtual = 0) and then deriving your concrete classes from it.
Down sides of this:
- All your public calls become virtual (some optimizations can bypass this, but not often).
- You can't 'new up' your classes anymore, you'll need to implement a factory pattern.
The problem with any of the other hacks I'm familiar with is that they basically declare the methods in one set of headers, and then redeclare the same things with the 'real' implementation in private headers - depending on the linker to match up the names. A couple problems here are:
Maintaining this mess sucks. You can't use an #ifdef because it sounds like you want to physically hide your implementation. So you have dual maintaining, or a build step that generates your public headers.
Can only be used via pointer. You have to play games making constructors private and still have a factory because the compiler won't generate structs of the right size if you let the client gen it by value (or even with new).
Finally, I once saw a hack where the programmer tried to declare a byte array in the private area of the 'public' class so that the client code could still declare by value or 'new' it themselves. This suffers all the previous problems, plus you probably don't want to have to 'know' the size of the structs since they depend on packing and alignment. Your 'build step' would more or less have to have a runtime component that used sizeof() - and now you have a versioning problem if you want to change the size of the struct/class.

Define a Forward-defined C++ struct by aliasing

I want to write a C-wrapper around an existing C++ codebase. So I need to implement some C-API functions that merely forward their operations to the corresponding C++ methods.
My problem is, I cannot figure out how to implement a forward-defined struct by means of an existing class:
//Foo.hpp
namespace myLib {
struct Foo {
//some meaningful C++ body
};
}
//foo.h
//#ifdef __cplusplus etc. left out
extern "C" {
struct myLib_foo;
myLib_foo* mkfoo();
//etc.
}
//foo.cpp
extern "C" {
#include "Foo.hpp"
#include "foo.h"
typedef myLib_foo myLib::Foo; //this does not work
myLib_foo* mkfoo() { return new myLib::Foo(); }
}
In this situation, the C-API can and shall only work with pointers to myLib::Foo, which obviously works well, if I define myLib_foo as a new struct inside foo.cpp. I guess it also works, if I define a struct myLib_foo somewhere else. Yet, since I want to keep my namespaces manageable, I am searching a way to define myLib_foo to be equivalent to some existing (and completely defined) struct. This, however does not work, since my compiler refuses the code above with "typedef redefinition with different types". Apparently, it distinguishes between type-aliases and structs.
Is there even a way to achieve what I want or does C++ have no means for real type-aliases?
edit:
By the answer below, I figured I can use inheritance plus static_cast:
//foo.cpp
extern "C" {
#include "Foo.hpp"
#include "foo.h"
struct myLib_foo : public myLib::Foo {}; //this does work
myLib_foo* mkfoo() { return static_cast<myLib_foo*>(new myLib::Foo()); }
}
The C code does not ever need a definition of the struct myLib_foo that it sees.
It handles it only through pointers and functions.
On the C++ side a simple implementation is a struct containing a pointer to the "real" object that it represents. You then define it in the ordinary way (in the C++ code), but of course with the name already established for the C code usage.
If you want to avoid even that little inefficiency, to hand out real object pointers to the C code, well then you have essentially two options:
reinterpret_cast, or
static_cast with the not-quite-C struct as a (possibly empty) base class.
But I would go for the simple implementation of myLib_foo as a struct with a pointer to the real one. The KISS principle: Keep It Simple, Stupid*. On second thoughts, to avoid allocation and deallocation issues, and to also avoid a formal dependency on the compiler (even if that would just be academic, a formality), I would go for the static_cast. For thinking about what it all entails, this seems simplest.
*: Oh, the last few times I mentioned this principle on SO, those answers were heavily downvoted. That has also happened when I have (correctly) proposed macros as solutions. I think one should be technically honest and ignore the general SO readership, so I mention it anyway.

Define forward declared C-struct as C++-struct

Is it legal to forward-declare a struct as a C-struct
// api.h
#ifdef __cplusplus
extern "C" {
#endif
typedef struct handle_tag handle_t;
handle_t *construct();
void destruct(handle_t *h);
void func(handle_t *h);
#ifdef __cplusplus
}
#endif
and subsequently define it as a C++-struct, i.e. as a non-POD type?
// api.cpp
struct handle_tag {
void func();
std::string member;
};
void func(handle_t *h) {
h->func();
}
The general intention is to get via a C interface an externally accessible opaque type handle_t which is internally implemented as an C++ data type.
Yes, that will work fine as long as the C code never needs to see "inside" the handle_tag structure, and the appropriate C++ construction/destruction is performed by the C++ code (which I preseume the construct and destruct are for).
All that the C code needs is a pointer to some datastructure - it won't know what the contents is, so the content can be anything you like it to to be, including constructor/destructor reliant data.
Edit:
I should point out that this, or methods similar to it (e.g. using a void * to record the address of an object for the C portion to hold), is a fairly common way to interface C-code to C++ functionality.
Edit2:
It is critical that the C++ code called doesn't "leak" exceptions into the C code. That is undefined behaviour, and very much liable to cause crashes, or worse, "weird things" that don't crash... So unless the code is guaranteed to not cause exceptions (and for example std::string is liable to throw bad_alloc in case of low memory), it is required to use a try/catch block inside code like construct anf func in the C++ side.
Won't work quite as is, but the concept's ok. When the functions are defined, you also need to make sure the names aren't mangled so that the C code can find them. That means #include "api.h" should be added atop your api.cpp file.