Classes
Contents
We are able to define our own types using classes. Sometimes we may want the class types to work with operators in a manner that we use with primitive types.
The "this" keyword is used to denote a pointer to the class object and can be used only inside the class.
File: oo1.cpp
#include <iostream> using namespace std ; class point { public: int x1 ; int y1 ; point( int x1 , int y1 ) { this->x1 = x1 ; this->y1 = y1 ; } }; int main() { return 0 ; }The "this" is a pointer to the object and in the above code we are using it to refer to the variables "x1" and "y1" in the class as the variables in the argument are also called "x1" and "y".
File: oo2.cpp
#include <iostream> using namespace std ; class point { public: int x1 ; int y1 ; point operator+( const point& param1 ); }; point point::operator+( const point& param1 ) { cout << "Calling operator + member function." << endl ; point pointObj ; pointObj.x1 = x1 + param1.x1 ; pointObj.y1 = y1 + param1.y1 ; return pointObj ; } int main() { point point1 ; point1.x1 = 1 ; point1.y1 = 1 ; point point2 ; point2.x1 = 2 ; point2.y1 = 2 ; point point3 ; point3 = point1 + point2 ; cout << point3.x1 << " " << point3.y1 << endl ; return 0 ; }
In the above we have a point class that represents a 2 dimensional co-ordinate. We want to be able to add 2 objects of the point class by using an expression of the form: point1 + point 2 We define a member function with the signature: point operator+( const point& param1 ); The method name is "operator+" and it contains an argument that takes a point object. We can specify different arguments as well as a different return type also. Inside this function we create a new object that is returned. The function gets invoked when we execute the statement: point3 = point1 + point2 ; The member function "operator+" gets called for the object "point1" and the object "point2" gets passed in as the argument. The following list shows the symbols that we can use for operator overloading. + - * / % ^ & | ~ ! , = < > <= >= ++ -- << >> == != && || += -= /= %= ^= &= |= *= <<= >>= [] () -> ->* new new [] delete delete [] Let's say that we want to be able to do something like: point + 5 The integer 5 will be added to the x-coordinate and the y-ordinate. We can add another member function.
File: oo3.cpp
#include <iostream> using namespace std ; class point { public: int x1 ; int y1 ; point operator+( const point& param1 ); point operator+( int param1 ); }; point point::operator+( const point& param1 ) { cout << "Calling operator + member function." << endl ; point pointObj ; pointObj.x1 = x1 + param1.x1 ; pointObj.y1 = y1 + param1.y1 ; return pointObj ; } point point::operator+( int param1 ) { cout << "Calling operator + member function with an integer argument." << endl ; point pointObj ; pointObj.x1 = x1 + param1 ; pointObj.y1 = y1 + param1 ; return pointObj ; } int main() { point point1 ; point1.x1 = 1 ; point1.y1 = 1 ; point point2 ; point2.x1 = 2 ; point2.y1 = 2 ; point point3 ; point3 = point1 + point2 ; cout << point3.x1 << " " << point3.y1 << endl ; point3 = point1 + 5 ; cout << point3.x1 << " " << point3.y1 << endl ; return 0 ; } $ g++ oo3.cpp ; ./a.exe Calling operator + member function. 3 3 Calling operator + member function with an integer argument. 6 6We can see that "C++" is quite flexible as far as the operator and the arguments. There is another way we could have created the "+" function and that is by making the function global ( not inside the class ) and making it into a friend.
File: oo4.cpp
#include <iostream> using namespace std ; class point { public: int x1 ; int y1 ; friend point operator+( const point& param1 , const point& param2 ); }; point operator+( const point& param1 , const point& param2 ) { cout << "Calling operator +" << endl ; point pointObj ; pointObj.x1 = param1.x1 + param2.x1 ; pointObj.y1 = param1.y1 + param2.y1 ; return pointObj ; } int main() { point point1 ; point1.x1 = 1 ; point1.y1 = 1 ; point point2 ; point2.x1 = 2 ; point2.y1 = 2 ; point point3 ; point3 = point1 + point2 ; cout << point3.x1 << " " << point3.y1 << endl ; return 0 ; }
When we call the statement point3 = point1 + point2 ; the global function : point operator+( const point& param1 , const point& param2 ) is invoked. Since it's a global function both the "point1" and "point2" objects are passed to the function. We can use the member function or the global function approach to implement the "+" operator. Which one should we use ? If an operation can be done using the class member function then we should use that. This reduces the number of global functions that are introduced. Sometimes the argument on the left hand side is not that of the class we want to implement the operator for and in that case we have no choice but to use the global function. Wouldn't it be nice if we just use cout << pointObject ; syntax to print out the contents of the "point" class. We can overload the operator "<<" but since "cout" is not of the point class we have to use a global function. The "cout" is an object of the "ostream" class and this class also has overloaded operators for the "<<" operator. If we write something such as: cout << "table" << 5 << endl ; The member function gets called for : cout << "table" This will pass the string "string" to the cout member function and that function will print the "table" and return the same "cout" object. Now we have something like: table cout << 5 << endl ; We have printed "table" on the screen and now we have the same cout object ready to work on the next argument which happens to be 5. Let us implement a global function for our point class.
File: oo5.cpp
#include <iostream> using namespace std ; class point { public: int x1 ; int y1 ; point operator+( const point& param1 ); friend ostream& operator<<(ostream& os, const point& param1) ; }; point point::operator+( const point& param1 ) { cout << "Calling operator + member function." << endl ; point pointObj ; pointObj.x1 = x1 + param1.x1 ; pointObj.y1 = y1 + param1.y1 ; return pointObj ; } ostream& operator<<(ostream& os, const point& param1) { os << param1.x1 << " " << param1.y1 << endl ; return os; } int main() { point point1 ; point1.x1 = 1 ; point1.y1 = 1 ; point point2 ; point2.x1 = 2 ; point2.y1 = 2 ; cout << point1 << endl ; cout << point2 << endl ; return 0 ; } $ g++ oo5.cpp ; ./a.exe 1 1 2 2Using the subscript operator.
Let's say we had a class and we wanted to give the user the ability to use the array index operator on our class. We can do that by overloading the array index operator.
File: oo6.cpp
#include <iostream> using namespace std ; class myVector { public: int* ptr ; int size ; myVector(int sizeP ) { size = sizeP ; ptr = new int[sizeP] ; for( int i1=0 ; i1< size ; i1++ ) { ptr[i1] = i1+1 ; } } ~myVector() { if ( ptr != NULL ) delete[] ptr ; } int& operator[] (int index) { return ptr[index] ; } void print() { for( int i1=0 ; i1<size ; i1++ ) cout << ptr[i1] << " " ; cout << endl ; } } ; int main() { myVector obj1(2) ; obj1.print() ; obj1[0] = 100 ; obj1.print() ; return 0 ; } $ g++ oo6.cpp ; ./a.exe 1 2 100 2
We created the copy constructor for our "mystring" class previously. If we didn't have a copy constructor then we run into memory delete issues. The same problem happens when we use the default assignment operator. If we have 2 objects of mystring such as "mystring1" and "mystring2" then: mystring2 = mystring1 leads to the same problem. Also we want to be able to add 2 mystring objects using the "+" operator such as: mystring1 + mystrin2 Implement 3 additional functions : assignment operator, + operator and the "<<" operator . Remember the assignment operator should return an object and not void so that we can use it in situations like: mystring3 = ( mystring2 = mystring1 ) ; We can do that by returning the object "*this" .
File: mystring.h
File: mystring.cpp
File: main.cpp