I do not agree with @sechastain .
Attachment is not automatic. Regardless of whether the method is in place or a hint (the inline or __forceinline ), the compiler is the only one who can decide whether the attachment will actually take place and uses complex heuristics for this. However, one specific case is that it should not cause a call when invoking a virtual method using dispatch at run time, precisely because dispatch and insert are incompatible.
To understand the accuracy of "using runtime scheduling":
IClassInterface* i = /**/; i->LOL(); // runtime dispatch i->QueueClass::LOL(); // compile time dispatch, inline is possible
@0xDEAD BEEF : I think your design is fragile, to say the least.
Using C-Style is wrong in this case:
QueueClass* p = ; IClassInterface* q = p; assert( ((void*)p) == ((void*)q) );
In principle, there is no guarantee that the 2 addresses are equal: this implementation is defined and is unlikely to resist change.
I want you to be able to safely use the void* pointer for the IClassInterface* pointer, then you need to first create it from IClassInterface* so that the C ++ compiler can do the correct pointer arithmetic depending on the layout of the objects.
Of course, I will also emphasize than using global variables ... you probably know this.
Regarding the reason for the absence? I honestly don't see anything but an error in the compiler / linker. Several times I saw the built-in definition of virtual functions (more specifically, the clone method), and it never caused problems.
EDIT : since “proper pointer arithmetic” was not so well understood, here is an example
struct Base1 { char mDum1; }; struct Base2 { char mDum2; }; struct Derived: Base1, Base2 {}; int main(int argc, char* argv[]) { Derived d; Base1* b1 = &d; Base2* b2 = &d; std::cout << "Base1: " << b1 << "\nBase2: " << b2 << "\nDerived: " << &d << std::endl; return 0; }
And here is what was printed:
Base1: 0x7fbfffee60 Base2: 0x7fbfffee61 Derived: 0x7fbfffee60
Not the difference between b2 and &d , although they refer to the same object. This can be understood if you think about the layout of the memory object.
Derived Base1 Base2 +-------+-------+ | mDum1 | mDum2 | +-------+-------+
When converting from Derived* to Base2* compiler will perform the necessary settings (here, increase the address of the pointer by one byte) so that the pointer is effective by pointing to Base2 part of Derived and not to part Base1 , mistakenly interpreted as an object Base2 (which would be nasty) .
This is why the use of C-Style casts should be avoided in suppression. Here, if you have a Base2 pointer, you cannot interpret it as a Derived pointer. Instead, you will need to use static_cast<Derived*>(b2) , which will reduce the pointer by one byte so that it correctly points to the beginning of the Derived object.
Manipulating pointers is usually called pointer arithmetic. Here, the compiler will automatically perform the correct configuration ... provided that the type is recognized.
Unfortunately, the compiler cannot execute them when converting from void* , so the developer must make sure that he does this correctly. A simple rule of thumb: T* -> void* -> T* with the same type that appears on both sides.
Therefore, you should (simply) fix your code by declaring: IClassInterface* globalMember , and you would not have a portability problem. You will probably still have a maintenance problem, but a problem with using C with OO code: C is not aware of any object oriented things.