|
Pointers To Members and their power Author: Shivesh Viswanathan Before introducing you to pointer-to-member, I will give you an application of it because you will realize the power of it through that example. You will have to assume certain things and be patient till you are through with this document. You have a rectangle class, which has four members, left, top, right, bottom. Your header file looks like this:
#ifndef __TEST_H__
#define __TEST_H__
class Rect
{
public:
Rect()
{
left = top = right = bottom = 0;
}
long left;
long top;
long right;
long bottom;
};
class Arbitrator
{
public:
Arbitrator( long Rect::* pSomeMemberOfRect ) : m_pSomeMemberOfRect( pSomeMemberOfRect )
{
}
long Rect::* m_pSomeMemberOfRect;
};
// This is your main class
class Main
{
public:
Main()
{
// Default arbitrator is left
m_currentArbitrator = &arbLeftOfRect;
}
void foo();
static Arbitrator arbLeftOfRect;
static Arbitrator arbTopOfRect;
static Arbitrator arbRightOfRect;
static Arbitrator arbBottomOfRect;
Arbitrator* m_currentArbitrator;
};
#endif // __TEST_H__
You might wonder what long rect::* (type of m_pSomeMemberOfRect) is and why it can't be long*. Well, the answer will be evident to you a little later. Be patient. Now let us look at the .cpp of this file.
#include "test.h"
#include "iostream.h"
#include "string.h"
// Define the static member variables...
// They are defined with the appropriate members of rect.
// Do not get surprised by the &Rect::left...etc. they have a meaning...
// And I will explain it a little later...
Arbitrator Main::arbLeftOfRect(&Rect::left);
Arbitrator Main::arbTopOfRect(&Rect::top);
Arbitrator Main::arbRightOfRect(&Rect::right);
Arbitrator Main::arbBottomOfRect(&Rect::bottom);
int main( int argc, char* argv[] )
{
Main mainObj;
if( argc != 2 )
{
cout << "Usage: test <left/right/top/bottom>" << endl;
return 1;
}
if( !strcmp( argv[1], "left" ) )
{
mainObj.m_currentArbitrator = &Main::arbLeftOfRect;
}
else if( !strcmp( argv[1], "top" ) )
{
mainObj.m_currentArbitrator = &Main::arbTopOfRect;
}
else if( !strcmp( argv[1], "right" ) )
{
mainObj.m_currentArbitrator = &Main::arbRightOfRect;
}
else if( !strcmp( argv[1], "bottom" ) )
{
mainObj.m_currentArbitrator = &Main::arbBottomOfRect;
}
else
{
cout << "Type left/right/top or bottom" << endl;
return 1;
}
mainObj.foo();
return 0;
}
void Main::foo()
{
// Assume you are getting the rect from somewhere
Rect rect;
rect.left = 1;
rect.top = 2;
rect.right = 3;
rect.bottom = 4;
// notice this line...
int xy = rect.*m_currentArbitrator->m_pSomeMemberOfRect;
cout << xy << endl;
}
Compile the above code and type this on the command line...
test left
Now type this...
test right
You should get 1 as the output in the first case and 3 in the second case. Can you figure out what happened? I will tell you what certain bizarre pieces of code mean and leave it to you to put the pieces together. If you are not the doc reading types, debug the code and you will learn more than what I explain here. First, what does &Rect::left or &Rect::right mean? It means the address of the left variable RELATIVE to the beginning of the rect object. Now, during the static initializations, you do not have a rect object. But what you do have is the offset of left member or right member from any rect object. Here, the offset of left is 0 (because it is the first member) and hence, the value of &Rect::left is 0x00000000. Similarly, the offset of top is 4 bytes. So, &Rect::top will be 0x00000004 and so on for right and bottom. Now, we also understand that the line *pI // pI being a pointer to int and it's value = 0x3d4f0b9f... means, "get the content at the memory address 0x3d4f0b9f bytes away from 0x00000000". Now that we have understood these two important pieces of information, what is a pointer-to-member? If you come across a line, rect.*pI // pI being a pointer to int INSIDE A Rect class and it's value = 0x00000004 Should it make sense? It should and it does. I have added the rest of the code just to make this point evident. If it is still not clear, I will explain what the above line of code means. It means, "get the content at the memory address 0x00000004 bytes away from &rect". It is the offset of the member inside it's class or structure. Feel free to copy and paste the above .h and .cpp code and do whatever to understand this powerful concept. One last bit. A "normal" pointer cannot be type-casted to pointer-to-member. The compiler cribs. But try it out. Mail a question to the author!! As part of the IDevResource commitment to Open Publishing, all of our authors are available to answer all of your trickiest questions at Author Central. For information about the authors, or to mail a question, visit them at Author Central. Contribute to IDR: To contribute an article to IDR, a click here.
|
|