Page 1 of 1

C++ THIS POINTER TUTORIAL C++ THIS POINTER TUTORIAL Rate Topic: -----

#1 Elcric  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 102
  • View blog
  • Posts: 453
  • Joined: 02-May 09

Posted 10 August 2009 - 10:16 AM

C++ THIS POINTER TUTORIAL


WHAT YOU WILL LEARN IN THIS TUTORIAL:
1. You will learn when the this pointer can be used.
2. You will learn why the compiler implicitly passes the this pointer.
3. You will learn why the this pointer is not an ordinary variable.
4. You will learn why the this pointer is important to operator overloading.
5. You will learn the three things explicitly stated by a class member function’s declaration.
6. You will learn the three functions the this pointer can not be used with.
7. You will learn how the this pointer enables cascaded function calls.
8. You will learn how the this pointer is used with linked-list manipulation.

• I. INTRODUCTION

Hello; nice to meet you! Welcome to the “C++ this Pointer Tutorial.”

Attached is the example program which will be discussed in this tutorial:

//**************************************
//C++ THIS-> POINTER TUTORIAL
//**************************************
#ifndef CALC_ERROR_H
#define CALC_ERROR_H
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>				
#include <string>

using namespace std;
#endif  //CALC_ERROR_H

class C
{

public:

	static int objectCount;			  //Count of object in existence.

	C( int a );						  //Constructor.
	C( const C & );					  //Copy constructor.
	void m_Test2( C &CO );			   //Enables Cascaded Function Calls. 
	void ClearScreen() const;			//Clears the screen.
	void Pause() const;				  //Waits for user response.
	void DisplayNumberExistingObjects( C &CO ) const;  //Displays number of existing objects.
	void m_SetA( int a, string title );  //Displays proof of equality of statements.
	int  m_GetA();					   //Provides access to data member.
	void m_SizeOfFile();				 //Computes and displays the size of the file.
	C& m_Add( int a ){	its_a += a;	return *this; }	  //Inline add.
	C& m_Subtract( int a ){	its_a -= a;	return *this; }  //Inline subtract.
	C& m_Multiply( int a ){	its_a *= a;	return *this; }  //Inline multiply.
	C& m_Divide( int a ){	its_a /= a;	return *this; }  //Inline divide.
	~C();						   //Destructor.  
private:

	int its_a;

};

//************************************
//Constructor.
//************************************ 
C::C( int a )  
{
	string title = "CONSTRUCTOR:";
	m_SetA( a, title );
	objectCount++;
}

//************************************
//Copy constructor.
//************************************ 
C::C( const C & )
{
	objectCount++;
}

//************************************
//SetA
//Three equivalent statements.
//************************************ 
void C::m_SetA( int a, string title )
{
	//It is legal, though unnecessary, to explicitly use this
	//when referring to members of the class.
	ClearScreen();
	cout << "  " << title;
	if ( title == "TEST 1:" )
	{
		cout << "  CO.m_SetA( 2, 'TEST 1:' );";
	}
	cout << endl << endl;
	cout << "  its_a = a; = ";
	its_a = a;		 // <== These three statements are equivalent.
	cout << m_GetA();
	cout << endl << endl;

	cout << "  this->its_a = a; = ";
	this->its_a = a;   // <== These three statements are equivalent.
	cout << m_GetA();
	cout << endl << endl;

	cout << "  (*this).its_a = a; = ";
	(*this).its_a = a; // <== These three statements are equivalent.
	cout << m_GetA();
	cout << endl << endl;

	cout << "  All three statements are equivalent. " << endl << endl;


	Pause();
}

//************************************
//GetA
//************************************ 
int  C::m_GetA()
{
	return this->its_a;
}

//************************************
//This function computes and displays
//the size of the file.
//************************************
void C::m_SizeOfFile()
{
	long begin;							  //Instantiates begin as an object of class type long.
	long end;								//Instantiates end as an object of class type long.
	ifstream myfile ( "ExampleFile.dat" );   //Determine whether the stream object is currently associated with a file, if so, file is open.
	begin = myfile.tellg();				  //tellg(); is used to get the beggining position in the stream 
	myfile.seekg ( 0, ios::end );			//after it has been moved with seekg(); to the end of the stream;
											 //therefore, determining the size of the file.
	end = myfile.tellg();					//tellg(); is used to get the ending position in the stream 
	myfile.close();						  //closes file.					
	ClearScreen();
	cout << "  File size is: " << ( end - begin ) << " bytes." << endl;	   //end - begin determines size of the file.
	Pause();
}

//************************************
//Test2,
//enabling cascaded function calls.
//************************************

void C::m_Test2( C &CO )  //Passing an object to a function.
{
	CO.ClearScreen();
	cout << "  Initial value of data member is " << CO.m_GetA() << endl << endl;
	CO.m_Add( 2 );
	cout << "  Value of data member after addition of 2 is " << CO.m_GetA() << endl << endl;
	CO.m_Subtract( 1 );
	cout << "  Value of data member after subtraction of 1 is " << CO.m_GetA() << endl << endl;
	CO.m_Multiply( 10 );
	cout << "  Value of data member after multiplication by 10 is " << CO.m_GetA() << endl << endl;
	CO.m_Divide( 5 );
	cout << "  Value of data member after division by 5 is " << CO.m_GetA() << endl;
	CO.Pause();
	CO.ClearScreen();
	cout << endl << endl;
	this->its_a = 2;
	cout << "  New initial value of data member is " << CO.m_GetA() << endl << endl;
	CO.m_Add( 2 ).m_Subtract( 1 ).m_Multiply( 10 ).m_Divide( 5 );
	cout << "  After processing the following function" << endl << endl;
	cout << "  which enables a cascaded function call:" << endl << endl;
	cout << endl << endl << "  ";
	cout << "CO.m_Add( 2 ).m_Subtract( 1 ).m_Multiply( 10 ).m_Divide( 5 );" << endl << endl;
	cout << "  Final cascaded value of data member is " << CO.m_GetA() << endl << endl;
	cout << endl;
	CO.Pause();
}

//************************************
//Clear Screen.
//************************************
void C::ClearScreen() const
{
	system( "CLS" );
	cout << endl << endl << endl;
}

//************************************
//Pause.
//************************************
void C::Pause() const
{
	cout << endl << endl << endl;
	cout << "  ";
	system( "PAUSE" );
}

//************************************
//Computes and displays number of
//objects in existence.
//************************************
void C::DisplayNumberExistingObjects( C &CO ) const
{
	ClearScreen();
	cout << endl << endl << endl;
	cout << "  Number of existing class C objects: ";
	cout << C::objectCount;
	Pause();
}

//************************************
//Destructor
//************************************
C::~C()  
{

}

int C::objectCount = 0;  //Initialize static member of C class.

//************************************
// MAIN() FUNCTION.
//************************************
int main(int argc, char* argv[])
{
	int	 choice	=	0;
	bool	exitt	 =	false;
	//************************************

	C CO( 0 );  //Instantiate class member object CO of type C.

	do
	{
		CO.ClearScreen();
		cout << "			  C++ this-> Pointer Tutorial			"  << endl << endl;
		cout << "  ---------------------------------------------------"  << endl << endl;
		cout << "	0  Quit, exits program.						  "  << endl << endl;
		cout << "	   STEP 1a: Constructor equivalency.			 "  << endl << endl;
		cout << "	1  STEP 1b: Poof of equivalency:				 "  << endl;
		cout << "	   its_a = a;									"  << endl;
		cout << "	   this->its_a = a;							  "  << endl;
		cout << "	   (*this).its_a = a;							"  << endl << endl;
		cout << "	2  STEP 2: Proof enables cascaded function calls."  << endl << endl;
		cout << "	3  STEP 3: Displays number objects in existence. "  << endl << endl;

		cout << endl << endl;
		cout << "	Please type a number from 0 to 3 " << endl << endl;
		cout << "	then press Enter ==> ";

		cin >> choice;

		switch(choice)	//Start switch.
		{
		case (0):
			exitt	 =	true;
			return EXIT_SUCCESS;
			break;

		case (1):
			//************************************
			//Compute and display Test1.
			//Initializing a data member.
			//************************************
			{
				CO.m_SetA( 2, "TEST 1:" );
			}
			//************************************
			break;

		case (2):
			//************************************
			//Compute and display Test2.
			//
			//************************************
			{
				CO.m_Test2( CO );  //Passing an object to a function
								   //by reference.
			}
			//************************************
			break;

		case (3):
			//************************************
			//Compute and display number of 
			//objects in existence.
			//************************************
			{
				CO.DisplayNumberExistingObjects( CO );	  
			}
			//************************************
			break;

		default:
			CO.ClearScreen();
			cout << "  Switch default error message! ";
			CO.Pause();
			break;
		}				 //End switch.

	}while( choice != 0 );

	return EXIT_SUCCESS;
}



• II. THE COMPILER

The C++ keyword this is a special type of pointer. Most uses of the this pointer are implicit and most of the time you will not need to access it directly. You do not have to worry about creating or deleting the this pointer, it is created and deleted by the compiler.

Class member functions manipulate the correct class object data member because each object has its own address which is pointed to by its this pointer. The compiler makes the this pointer available as a local variable within the body of non-static member functions to point to the class object the class member function is working with.

The this pointer is passed by the compiler as an implicit hidden argument to each of the object’s non-static member functions when the member function is called. For example, in the attached example program, in the main() function we have the following function call:

CO.m_SetA( 2, "TEST 1:" );



This function’s declaration, definition, and call all show two parameters. The compiler works with the called function as if it were written with the following three arguments:

m_SetA(& CO, 2, "TEST 1:");

By this automatic internal conversion the compiler converts member function calls to add an argument which passes in the address of the class object.

The compiler has to maintain the same number of parameters in the function’s declaration, definition, and call. Therefore, the compiler also does an automatic internal conversion on the function’s declaration and definition by changing the function definition from:

//************************************
//SetA
//Three equivalent statements.
//************************************ 
void C::m_SetA( int a, string title )
{
	//It is legal, though unnecessary, to explicitly use this
	//when referring to members of the class.
	ClearScreen();
	cout << "  " << title;
	if ( title == "TEST 1:" )
	{
		cout << "  CO.m_SetA( 2, 'TEST 1:' );";
	}
	cout << endl << endl;
	cout << "  its_a = a; = ";
	its_a = a;		 // <== These three statements are equivalent.
	cout << m_GetA();
	cout << endl << endl;

	cout << "  this->its_a = a; = ";
	this->its_a = a;   // <== These three statements are equivalent.
	cout << m_GetA();
	cout << endl << endl;

	cout << "  (*this).its_a = a; = ";
	(*this).its_a = a; // <== These three statements are equivalent.
	cout << m_GetA();
	cout << endl << endl;

	cout << "  All three statements are equivalent. " << endl << endl;


	Pause();
}



to:

void C::m_SetA( C* const this, int a , string title )
{
...
this->its_a = a;
...
}

The compiler has automatically converted the function’s declaration and definition by adding a new parameter. The added parameter is a hidden this pointer that points to the class object the class member function is working with.

The this pointer can be used implicitly by the compiler and explicitly by the programmer to access an object’s data members.

• III. THIS IS NOT AN ORDINARY VARIABLE

The keyword this is a pointer to the object for which a nonstatic member function is invoked; however, this is not an ordinary variable:
1. It is not possible to take the address of this.
2. It is not possible to declare this.
3. It is not possible to assign to this, it’s not an l-value; therefore, it can not be made null or zero.
4. It is not possible to modify this. You can change the value of the object it points to; however, you can not make it point to something else. The this pointer is a const pointer.
5. An object's this pointer is not part of the object itself; therefore, the size of this is not included when computing the size of an object.
6. The this pointer is also used to guard against self-reference and to resolve ambiguity.

• IV. OVERLOADING OPERATORS

The this pointer's type can be modified in the function declaration by the const and volatile keywords. To declare a function as having the attributes of one or more of these keywords, add the appropriate keywords after the function argument list. Examples are as follows: In a member function of a class C, the type of this is C*. The type of this if the member function is declared const, is const C*. The type of this if the member function is declared volatile, is volatile C*. The type of this If the member function is declared const volatile, is const volatile C*.

The this pointer is very important when operators are overloaded. For example, when the binary operator+(), which takes only one parameter, is overloaded it is the object on the left that generates the call to the operator function. Member functions use the this pointer implicitly to obtain the left operand for binary operators. This was demonstrated in “The Compiler” section of this tutorial.

• V. CLASS MEMBER FUNCTIONS

Member function declarations explicitly state the following:
1. The member function must be invoked on an object; which means the member function has a this pointer passed to it implicitly by the compiler.
2. The member function can access the private part of a class declaration.
3. The member function is in the scope of the class.

You can refer to the particular class object that a member function is called for by using the this pointer in the body of the member function.

The this pointer is very important whenever a member function must utilize a pointer to the object that invoked it. Each member function contains an implicit handle, in the form of a pointer represented by the C++ keyword this, to the object on which it operates.

The object's address is available from within the member function as the this pointer. The expression *this is commonly used to return the current object from a member function.

Just a reminder, as shown in the attached example program, always declare all member functions that do not alter the class object for which they are called as const.

• VI. STATIC MEMBER FUNCTIONS, FRIEND FUNCTIONS, AND GLOBAL FUNCTIONS

The this pointer cannot be used with:
1. Static member functions.
A static member function is not passed a this pointer.
2. Friend functions.
Friend functions are not members of a class; therefore, they are not passed a this pointer.
3. Global functions.
Global functions are not passed a this pointer.

• VII. ENABLING CASCADED FUNCTION CALLS

The this pointer can be used to enable cascaded function calls.
Cascaded function calls are function calls that invoke multiple functions in the same statement sequentially using left to right precedence so that the output of one function becomes the input of the next function.

//************************************
//Test2,
//enabling cascaded function calls.
//************************************

void C::m_Test2( C &CO )  //Passing an object to a function.
{
	CO.ClearScreen();
	cout << "  Initial value of data member is " << CO.m_GetA() << endl << endl;
	CO.m_Add( 2 );
	cout << "  Value of data member after addition of 2 is " << CO.m_GetA() << endl << endl;
	CO.m_Subtract( 1 );
	cout << "  Value of data member after subtraction of 1 is " << CO.m_GetA() << endl << endl;
	CO.m_Multiply( 10 );
	cout << "  Value of data member after multiplication by 10 is " << CO.m_GetA() << endl << endl;
	CO.m_Divide( 5 );
	cout << "  Value of data member after division by 5 is " << CO.m_GetA() << endl;
	CO.Pause();
	CO.ClearScreen();
	cout << endl << endl;
	this->its_a = 2;
	cout << "  New initial value of data member is " << CO.m_GetA() << endl << endl;
	CO.m_Add( 2 ).m_Subtract( 1 ).m_Multiply( 10 ).m_Divide( 5 );
	cout << "  After processing the following function" << endl << endl;
	cout << "  which enables a cascaded function call:" << endl << endl;
	cout << endl << endl << "  ";
	cout << "CO.m_Add( 2 ).m_Subtract( 1 ).m_Multiply( 10 ).m_Divide( 5 );" << endl << endl;
	cout << "  Final cascaded value of data member is " << CO.m_GetA() << endl << endl;
	cout << endl;
	CO.Pause();
}



• VIII. LINKED-LIST MANIPULATION
Linked-list manipulation is a common explicit use of the this pointer in the event code is necessary to first checks if the left and right operands of operator= are the same object.

• IX. SUMMARY

As shown in the attached example program, using the class data member name is equivalent to using the class data member name with the this pointer and the -> class member access operator. You can explicitly use the keyword this pointer and the class member access operator -> when referring to data members of a class.

The this pointer is passed as an implicit argument by the compiler to each of a class’s non-static member functions. The this pointer provides the functions access to the correct object’s data members.

Each object has its own copy of data. When a member function is called the compiler has to be told by the programmer the class object and class member data the programmer wants the member function to use. The compiler in turn implicitly passes the this pointer to the member function when the member function is called to tell the member function the identity of the object whose data the member function will be working with.
Implicitly means with no programmer involvement. If the programmer adds the this pointer to the code then it is being stated explicitly by the programmer.

Is This A Good Question/Topic? 1
  • +

Page 1 of 1