I'm experimenting with C++ to understand how class/structures and their respective objects are laid out in memory and I understood that each field of a class/structure is an offset into their respective object (so I can have a member variable pointer).
I don't understand why, even if I can have member function pointers, the following code doesn't work:
struct mystruct
{
void function()
{
cout << "hello world";
}
int c;
};
int main()
{
unsigned int offset_from_start_structure = (unsigned int)(&((mystruct*)0)->c);
unsigned int offset_from_start_structure2 = (unsigned int)(&((mystruct*)0)->function); // ERROR - error C2276: '&' : illegal operation on bound member function expression
return 0;
}
My question is: why does the line
unsigned int offset_from_start_structure = (unsigned int)(&((mystruct*)0)->c);
compile and returns me the offset of the "c" field from the start of the structure and the line
unsigned int offset_from_start_structure2 = (unsigned int)(&((mystruct*)0)->function);
doesn't even compile?
Member functions or pointers to them aren't stored in the object. (virtual
functions are typically called through a pointer stored in a table to which an object has a single pointer to) This would be a huge waste of memory. They're typically stored in a code memory section, and are known to the compiler. The object (*this
) is typically passed as an invisible parameter so the functions know on which object to operate when they are called.
So, in layman terms, you'd have
0x10001000 void A::foo
.......... {code for A::foo}
and
push a;
call A::foo (0x10001000)
pop a;
where a
is the object you're calling foo
on.
Member function pointers are in practice not stored in objects: there's no need. The C++ standard doesn't specify exactly how e.g. virtual functions are to be implemented, but the common practice for virtual member functions is that each object contains a pointer to a table of function pointers; this pointer is called a vtable pointer.
You might try to get hold of “Inside the C++ object model” by Stanley Lippman.
Or, you might just try to get hold of my old pointers tutorial, which was once referenced from Wikipedia's pointers article, before my then homepage site disappeared.
Regarding the second question, why taking the address of p->memberFunc
makes the compiler choke a little, well that expression has no type, it's just a syntactical entity, which you can apply an argument list to in order to call the function.
To wit,
struct S
{
void foo() {}
};
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
S* p = 0;
typeid( &p->foo );
}
Compilation:
[W:\dev\test]
> g++ foo.cpp
foo.cpp: In function 'int main()':
foo.cpp:12:17: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say '&S::foo' [-fpermissive]
foo.cpp:12:22: warning: value computed is not used [-Wunused-value]
foo.cpp:12:22: warning: statement has no effect [-Wunused-value]
[W:\dev\test]
> _