What is the purpose of the following esoteric C++ operators?
Pointer to member
::*
Bind pointer to member by pointer
->*
Bind pointer to member by reference
.*
What is the purpose of the following esoteric C++ operators?
Pointer to member
::*
Bind pointer to member by pointer
->*
Bind pointer to member by reference
.*
A pointer to a member allows you to have a pointer that is relative to a specific class.
So, let's say you have a contact class with multiple phone numbers.
class contact
{
phonenumber office;
phonenumber home;
phonenumber cell;
};
The idea is if you have an algorithm that needs to use a phone number but the decision of which phone number should be done outside the algorithm, pointers to member solve the problem:
void robocall(phonenumber contact::*number, ...);
Now the caller of robocall can decide which type of phonenumber to use:
robocall(&contact::home, ...); // call home numbers
robocall(&contact::office, ...); // call office number
.*
and ->*
come into play once you have a pointer. So inside robocall, you would do:
contact c = ...;
c.*number; // gets the appropriate phone number of the object
or:
contact *pc = ...;
pc->*number;
Check out the C++ FAQ Lite's section on pointers to member functions. Search for the specific "operators" you're talking about (in most browsers, Ctrl-F opens a Find/Search dialog that allows you to search for text in the Web page), and it should help you to understand things better.
An oversimplified answer - these operators allow to call member functions as 'regular' functions (at least it looks the same from the end user's perspective) . Real world example - they are used a lot in a various callback implementations.
There's no such operator as ::*
and there's never been. I don't know where you got it.
As for ->*
and .*
- these are dereference operators for pointers of pointer-to-member type.
struct S {
int i;
};
int main() {
int S::*pi = &S::i; // pointer of pointer-to-member type
S s;
S* ps = &s;
s.*pi = 0; // operator `.*` used
assert(s.i == 0);
ps->*pi = 1; // operator `->*` used
assert(s.i == 1);
}
As for what pointers-to-members are... what does your favorite C++ book say on the subject?
These allow you to have pointers to member functions (and member variables) that are tied to a particular instance of the class.
Pointers to member functions can be useful for things like lightweight implementations of the state pattern. Generally, any time you want to vary the behavior of an object over time without resorting to switching out the entire object, you can consider the use of pointers to member functions.
Pointers to member variables can be used if you want to, e.g., implement a generic algorithm to search an array of structs for an entry that has a particular value for a given field.
They relate to pointers-to-members and pointers-to-member-functions.
struct Foo {
int a() { return 1; }
int b() { return 2; }
int c;
};
int main() {
Foo f;
f.c = 3;
typedef int (Foo::*member_fn)(); // pointer-to-member-function
typedef int (Foo::*data_member); // pointer-to-member
member_fn mf = &Foo::a;
(f.*mf)(); // calls the member function pointed to by mf. returns 1
mf = &Foo::b;
(f.*mf)(); // This time, returns 2, since mf points to b
Foo *fp = &f;
(fp->*mf)(); // same thing, via pointer to f instead of object/reference f.
data_member dm = &Foo::c;
f.*dm; // is 3
f.*dm = 5;
f.c; // is now 5.
Foo f2; // another instance
f2.c = 12;
f2.*dm; // is 12. Same pointer-to-member, different object.
}
Although it might look like one, ::*
isn't an operator. It's the ::
operator and the *
operator type modifier next to each other. To prove this without resorting to reading the standard, try adding spaces: :: *
compiles, . *
doesn't, neither does -> *
.
As for what they're actually useful for - same principle as function pointers. You wouldn't use them as I have above, in a situation where you could just call the function by name, but you can pass them as parameters or return them from functions, store them, or select one of several based on complicated logic.
If it helps, I believe the syntax is chosen so that although .*
is an indivisible single operator, you can imagine that *dm
"means" c
, the member pointed to by dm. So if dm
points to c
, then f.*dm
is the same as f.c
.