Normally pointers contain addresses. Why do pointers to member of a class contain offsets?
Talking about pointers to class data members, not pointers to member functions.
A pointer to a class member differs from a regular pointer in that it by itself doesn't actually point at a single location in memory. For example, if you have this setup:
struct MyStruct {
int x;
int y;
};
int MyStruct::* ptr = &MyStruct::y;
Then the pointer ptr
isn't actually pointing to a memory address because there is no one object MyStruct::y
. Rather, each instance of MyStruct
has its own copy of the data member y
.
The C++ standard doesn't mandate how pointers-to-member are actually implemented, but a common strategy is to have the pointer-to-member store an offset in bytes from the base of the object to the field in question. That way, when you write something like
MyStruct ms;
ms.*ptr = 137;
The compiler can generate code that says "go to the base address of ms
, skip forward a number of bytes specified by the value stored in ptr
, then write 137."
Pointers do not have to contain addresses. Pointers are tools to access a certain object indirectly - i.e. write code which would access an object which is unknown at compile time. Example:
a = 10; // It is known at compile time, 10 is written to object a
*pi = 10; // It is not known at compile time where 10 is written to
For normal objects, having address in the pointer is a cheapest way to achieve this goal (however, it won't be the case for C++ script!).
For members, though, normal address wouldn't work - there is no such thing as an address of a member of the class! You can only know the physical address of the member when you have a class object.
So, you have to use some sort of offset, which you than can translate to physical address once the actual object is known.
Pointers-to-members are not pointers.
The C++ type system contains several kinds of compound types, and there are two separate, sibling kinds of compound types that are not related to one another, despite having similar sounding names: Pointers, and "pointers to non-static class members". I'll call the latter "pointer-to-members", with hyphen, to stress that those are not a special kind of pointer, but really something entirely separate.
By the way, the type trait library separates the two concepts via std::is_pointer
and std::is_member_pointer
.
The two kinds of types serve entirely distinct purposes:
A pointer can represent the address of an object (or function) (or be null). That is, given a dereferenceable pointer, there is an actual concrete thing there that it's pointing at.
A pointer-to-member represents an abstract reference from a class to a non-static class member. Note that there are no objects involved. Such a pointer value does not point at anything concrete, and it has no concept of "dereferencing".
To repeat the final sentence: A pointer-to-member cannot be dereferenced, and it is not in any sense the address of an object. Rather, a pointer-to-member (specifically, to data member) can be applied to an object instance of its class, and together with the object it selects the subobject of that object corresponding to the class member that it represents. (Pointers-to-member-function have a slightly different notion of being applied to an instance; the result of the application is a function call.)
Returning to your question at last: A pointer holds an address of an object or function because it points at an object or function. A pointer-to-member does not hold an address, because it doesn't point at anything; it represents a relationship.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With