Operator overloading is the ability to tell the compiler how to perform a certain operation when its corresponding operator is used on one or more variables. For example, the compiler acts differently with regards to the subtraction operator “-“ depending on how the operator is being used. When it is placed on the left of a numeric value such as -48, the compiler considers the number a negative value. When used between two integral values, such as 80-712, the compiler applies the subtraction operation. When used between an integer and a double-precision number, such as 558-9.27, the compiler subtracts the left number from the right number; the operation produces a double-precision number. When the - symbol is doubled and placed on one side of a variable, such as --Variable or Variable--, the value of the variable needs to be decremented; in other words, the value 1 shall be subtracted from it. All of these operations work because the subtraction operator “-” has been reconfigured in various classes to act appropriately.
Suppose you create a class named TCountry as follows:
//---------------------------------------------------------------------------
struct TCountry
{
string Name;
Double Population;
Extended Area;
string Capital;
Char Government;
};
//---------------------------------------------------------------------------
|
Suppose you declare two TCountry variables such as:
TCountry SriLanka, BanglaDesh;
If you write an expression such as SriLanka + BanglaDesh and want to display the result, the compiler would need to know what you are trying to achieve. Do you want to add the names of the countries and create a new string name? Do you want to get the result of their combined populations, or the total or their areas? Operator overloading allows you to help the compiler perform this type of operation when it is applied on your
object(s).
Defaults Methods: A Review |
|
When studying constructors, we learned that, whenever you create an object, the compiler automatically creates some of its necessary methods. For example, you can create a TSquare class as follows:
//---------------------------------------------------------------------------
#include <iostream.h>
#include <iomanip.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
//---------------------------------------------------------------------------
struct TSquare
{
public:
void __fastcall setSide(const double s) { Side = s; }
double __fastcall getSide() const { return Side; }
double __fastcall Perimeter() const { return 4 * Side; }
double __fastcall Area() const { return Side * Side; }
private:
double Side;
};
//---------------------------------------------------------------------------
void __fastcall Properties(const TSquare& Carre)
{
cout << "Properties of the square";
cout << setiosflags(ios::fixed) << setprecision(2);
cout << "\nSide: " << Carre.getSide();
cout << "\nPerimeter: " << Carre.Perimeter();
cout << "\nArea: " << Carre.Area();
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TSquare CupHolder;
CupHolder.setSide(35.55);
Properties(CupHolder);
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
To start, if you do not create a constructor, the compiler would create one for you. This is called the default constructor. Otherwise, you can create your own:
//---------------------------------------------------------------------------
struct TSquare
{
public:
__fastcall TSquare();
void __fastcall setSide(const double s) { Side = s; }
double __fastcall getSide() const { return Side; }
double __fastcall Perimeter() const { return 4 * Side; }
double __fastcall Area() const { return Side * Side; }
private:
double Side;
};
//---------------------------------------------------------------------------
__fastcall TSquare::TSquare()
{
}
//---------------------------------------------------------------------------
|
In the same way, if you do not create a destructor, the compiler would also create one for you. Otherwise, you can create your own destructor:
//---------------------------------------------------------------------------
struct TSquare
{
public:
__fastcall TSquare();
virtual __fastcall ~TSquare();
void __fastcall setSide(const double s) { Side = s; }
double __fastcall getSide() const { return Side; }
double __fastcall Perimeter() const { return 4 * Side; }
double __fastcall Area() const { return Side * Side; }
private:
double Side;
};
//---------------------------------------------------------------------------
__fastcall TSquare::TSquare()
{
}
//---------------------------------------------------------------------------
__fastcall TSquare::~TSquare()
{
}
//---------------------------------------------------------------------------
|
To allow making copies of objects, the compiler also creates an appropriate constructor for you if you do not define one for your object. This is called the copy constructor. You can still explicitly create one as follows:
//---------------------------------------------------------------------------
struct TSquare
{
public:
__fastcall TSquare();
__fastcall TSquare(const TSquare& Q);
virtual __fastcall ~TSquare();
void __fastcall setSide(const double s) { Side = s; }
double __fastcall getSide() const { return Side; }
double __fastcall Perimeter() const { return 4 * Side; }
double __fastcall Area() const { return Side * Side; }
private:
double Side;
};
//---------------------------------------------------------------------------
__fastcall TSquare::TSquare()
{
}
//---------------------------------------------------------------------------
__fastcall TSquare::TSquare(const TSquare& Sq)
: Side(Sq.Side)
{
}
//---------------------------------------------------------------------------
__fastcall TSquare::~TSquare()
{
}
//---------------------------------------------------------------------------
|
In reality, there are four default functions that the compiler creates for you if you do not define them yourself. Besides the default constructor, the copy constructor, and the destructor, the compiler also create an overloaded assignment operator function for you. This can be easily seen on the code completion if you have not yet created this function for an object:
So far, we have been able to assign a variable declared from a class to another variable of the same type. Here is an example:
//---------------------------------------------------------------------------
void __fastcall Properties(const TSquare& Carre)
{
cout << "Properties of the square";
cout << setiosflags(ios::fixed) << setprecision(2);
cout << "\nSide: " << Carre.getSide();
cout << "\nPerimeter: " << Carre.Perimeter();
cout << "\nArea: " << Carre.Area();
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TSquare Holder, Loop;
Holder.setSide(35.55);
Properties(Holder);
cout << "\n\n";
Loop.setSide(18.04);
TSquare Base(Loop);
Properties(Base);
cout << "\n\n";
TSquare Sink = Holder;
Properties(Sink);
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
This assignment operation is possible because the compiler is configured to take care of it, using its own default created overloaded assignment operator function.
The C++ language recognizes 45 operators of various types. The most usual and the most regular operator is the output extraction operator << used to display anything in C++. The input >> operator is used to retrieve data input. Arithmetic operators are used to perform numeric operations. The unary operators are used to control the sign or behavior of a variable. There are many other binary and C++ specific operators. When customized, the arithmetic and any other operators can be applied to varying circumstances.
When overloaded, the operators are implemented as functions using the operator keyword. For example, the syntax of overloading the addition operator “+” would be operator+().
Overloading the Operators |
|
The assignment operator works by giving the value of one variable to another variable of the same type or closely similar. Suppose you declare two integer variables as follows:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A, B;
cout << "Values of variables";
cout << "\nA: " << A;
cout << "\nB: " << B;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
In reality (that is, on a different compiler, such as MSVC), this would produce:
Values of variables
A: 2.122e-314
B: 2.53936e-314
Press any key to continue…
|
As you can see, as long as a variable is not initialized, it holds a garbage value. Suppose you initialize the A variable as follows:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A, B;
A = 266.52;
cout << "Values of variables";
cout << "\nA: " << A;
cout << "\nB: " << B;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
This would produce:
Values of variables
A: 266.52
B: 2.53936e-314
Press any key to continue…
|
This time, once a variable has been initialized, it holds the appropriate value. Notice that the B variable that has not been initialized is still holding garbage. If you want to give the value of one variable to another variable, you can use the = operator between them as follows:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A, B;
A = 266.52;
cout << "Values of variables";
cout << "\nA: " << A;
cout << "\nB: " << B;
A = B;
cout << "\n\nValues of variables";
cout << "\nA: " << A;
cout << "\nB: " << B;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
The = sign implements the assignment operation. It works on two variables, one on each side of the symbol. After it has operated, the value that the right variable holds is given to the left variable. An example of executing the above program would be:
Values of variables
A: 266.52
B: 2.53936e-314
Values of variables
A: 2.53936e-314
B: 2.53936e-314
Press any key to continue…
|
Notice that although the A variable had been initialized previously, by assigning it to another variable, its value changes. On its second call, the A variable has lost its previous variable and hods whatever value the B variable was given.
If you want to assign the value of A to B, you would write:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A, B;
A = 266.52;
cout << "Values of variables";
cout << "\nA: " << A;
cout << "\nB: " << B;
B = A;
cout << "\n\nValues of variables";
cout << "\nA: " << A;
cout << "\nB: " << B;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
The first time the variables are called, the initialized A variable displays a recognizable value while B is still holding garbage. After B has been initialized, on the second call, both variables hold the same value:
Values of variables
A: 266.52
B: 2.53936e-314
Values of variables
A: 266.52
B: 266.52
Press any key to continue…
|
To use the assignment operator on your own object, you should (or must) let the compiler know how to handle the assignment operator on a variable declared from such an object. To do this, create your own implementation of the assignment operator.
The assignment operator is defined using the operator keyword followed by the = symbol and the traditional parentheses of every function. As a function, the operator must be declared in the body of the class, along with the other method members. In order for this function to be accessible outside of the class, it should be listed in the public section. Like any member method, the function should have a return value, at least void. Therefore it could be created as follows:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
public:
__fastcall TRectangle(double L = 0.00, double H = 0.00)
: Length(L), Height(H) {}
__fastcall TRectangle(const TRectangle& R)
: Length(R.Length), Height(R.Height) {}
__fastcall ~TRectangle() {}
void __fastcall setLength(const double L) { Length = L; }
double getLength() const { return Length; }
void __fastcall setHeight(const double H) { Height = H; }
double __fastcall getHeight() const { return Height; }
double __fastcall Perimeter() const { return 2 * (Length + Height); }
double __fastcall Area() const { return Length * Height; }
void operator=();
private:
double Length;
double Height;
};
//---------------------------------------------------------------------------
#endif
|
We saw earlier that, to perform an assignment, one variable is given the value of another, similar, variable, as in Var1 = Var2. The variable on the right is given the value of the variable on the left. For this operation, we must have a source variable (right) whose value we want to assign to the other variable (left). We must make sure that this source variable is the same type as the value we are trying to get; otherwise, the compiler would not be able to perform the operation. Therefore, the source variable will be provided as argument to the function; and this argument must be the same as the class on which the operation is applied. For this reason, the function operator can be created as:
void operator=(TRectangle Rect);
|
To assign one variable to another, there must be a correspondence between a member of the source variable and a member of the target or left variable. Therefore, the function operator can be implemented as follows:
//---------------------------------------------------------------------------
void TRectangle::operator=(TRectangle Rect)
{
Length = Rect.Length; Height = Rect.Height;
}
//---------------------------------------------------------------------------
|
The assignment operator is simply used to assign the value of a source variable to another variable. During this operation, the value of the source variable is not modified. Therefore, the argument should be passed as a constant. This changes the function to:
void operator=(const TRectangle Rect);
|
To speed up the retrieval of the value of the argument, you can let the compiler access the value of the argument directly to its address. This is done by passing the argument as reference. Since the argument is (also) passed as a constant, there is no modification of the value of the argument. The function can be declared as:
void operator=(const TRectangle& Rect);
|
We saw earlier that when one variable is assigned to another, as in B = A, the value of the source variable A is given to the target or left variable B. This means that, after the operation, the function should return a non-void variable. Since the new value of the variable must be the same as the source variable, the function should return a variable of the same class. The operator function would become:
TRectangle operator=(const TRectangle& Rect);
|
When a variable is assigned a value, its own value must change, regardless of the value it was holding; we saw this earlier when we called the A variable after it had been assigned the value of B. Therefore, the operation should return a reference to the type of object. This changes the decclaration of the function to:
TRectangle& operator=(const TRectangle& Rect);
|
From this, the function must return a value, since it is not defined with void anymore. The assignment operation is performed from one object to another object of the same kind. This means the function must return the same variable that called it. Therefore, the function must return the this pointer. Here is the correct implementation of the function:
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator=(const TRectangle& Rect)
{
Length = Rect.Length;
Height = Rect.Height;
return *this;
}
//---------------------------------------------------------------------------
|
Overloading the Arithmetic Operators |
|
In C++, the addition operation is applied with the + symbol. Depending on the circumstance, it can be considered a unary or a binary operator. It is used as a unary operator when applied to one variable.
The addition binary operator is used on two variables to add their values. Suppose you have two variables A and B. To add their values, you would type A + B. You can display such a value on the console as follows:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A, B;
A = 1266.52;
B = 3520.46;
cout << "Values of variables";
cout << "\nA = " << A;
cout << "\nB = " << B;
cout << "\nA + B = " << A + B;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
As you can see, the binary addition operator is performed on two variables. To apply it on a class, you must create a function operator that takes two arguments. Since the values of the arguments will not be modified, you should pass them as constant references. The function can be declared as follows:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
public:
__fastcall TRectangle(double L = 0.00, double H = 0.00)
: Length(L), Height(H) {}
. . .
TRectangle& operator=(const TRectangle& Rect);
void operator+(const TRectangle& x, const TRectangle& y);
private:
double Length;
double Height;
};
//---------------------------------------------------------------------------
#endif
|
To implement the function, you would add the values of the arguments. When performing this operation, there must be a correspondence between a variable of one argument and the equivalent variable of the other argument. Therefore, you would implement the function as follows:
//---------------------------------------------------------------------------
void TRectangle::operator+(const TRectangle& x, const TRectangle& y)
{
x.Length + y.Length;
x.Height + y.Height;
}
//---------------------------------------------------------------------------
|
If you execute the program with the function declared in the public section, you would get an error because C++ does not allow a binary operator to be overloaded (with two or more arguments) in a class. The solution is to declare the function outside of the class. The problem is that, to perform this binary operation, you will need access to the private or protected members of the class. Therefore, the operator function must be declared as a friend of the class:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
friend void operator+(const TRectangle& x, const TRectangle& y);
public:
__fastcall TRectangle(double L = 0.00, double H = 0.00)
: Length(L), Height(H) {}
. . .
TRectangle& operator=(const TRectangle& Rect);
private:
double Length;
double Height;
};
//---------------------------------------------------------------------------
#endif
|
Since the operator+() is not a member of the class anymore, its implementation becomes:
//---------------------------------------------------------------------------
void operator+(const TRectangle& x, const TRectangle& y)
{
x.Length + y.Length;
x.Length + y.Length;
}
//---------------------------------------------------------------------------
|
With this implementation of the function, the compiler does not complain anymore and the compilation is smooth. Also, it is now safe to add two variables declared from the TRectangle class:
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect(42.88, 36.14);
TRectangle Recto;
Recto + Rect;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
Since the operator+() function is declared as void, which means it does not return any value, it does not provide a value that can be displayed on the console. For example the following does not make sense:
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect(42.88, 36.14);
TRectangle Recto(16.52, 22.65);
cout << Recto + Rect;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
Refering to the former program that added A and B, instead of displaying the result of A + B on the console, you might want to store it in another variable. To do that, you would perform the addition and then assign the result to another variable. The assignment would appear as follows:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A, B, C;
A = 1266.52;
B = 3520.46;
C = A + B;
cout << "Values of variables";
cout << "\nA = " << A;
cout << "\nB = " << B;
cout << "\nC = " << C;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
This demonstrates that the binary addition applied on two variables in fact provides a third result; and this result is a variable of the same type. In other words, after performing the addition, the operator+() function must return a variable of the same type. The function should return TRectangle and can be declared as follows:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
friend TRectangle operator+(const TRectangle& x, const TRectangle& y);
public:
__fastcall TRectangle(double L = 0.00, double H = 0.00)
: Length(L), Height(H) {}
. . .
TRectangle& operator=(const TRectangle& Rect);
private:
double Length;
double Height;
};
//---------------------------------------------------------------------------
#endif
|
This time, the function must return a variable of the same type. During its implementation, you can declare a new variable of the same type, assign each of its variables to the equivalent added variable of the arguments, and then return that variable. Here is an example:
//---------------------------------------------------------------------------
TRectangle operator+(const TRectangle& x, const TRectangle& y)
{
TRectangle Room;
Room.Length = x.Length + y.Length;
Room.Height = x.Height + y.Height;
return Room;
}
//---------------------------------------------------------------------------
|
Now we can add two TRectangle variables and store the result in another variable:
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect(42.88, 36.14), Recto(16.52, 22.65), CDCase;
CDCase = Recto + Rect;
cout << "Properties of the CD Case";
Properties(CDCase);
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
To declare the other arithmetic operators, use the same syntax. Here is the header file:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
friend TRectangle operator+(const TRectangle& x, const TRectangle& y);
friend TRectangle operator-(const TRectangle& x, const TRectangle& y);
friend TRectangle operator*(const TRectangle& x, const TRectangle& y);
friend TRectangle operator/(const TRectangle& x, const TRectangle& y);
public:
__fastcall TRectangle(double L = 0.00, double H = 0.00)
: Length(L), Height(H) {}
__fastcall TRectangle(const TRectangle& R)
: Length(R.Length), Height(R.Height) {}
__fastcall ~TRectangle() {}
void __fastcall setLength(const double L) { Length = L; }
double getLength() const { return Length; }
void __fastcall setHeight(const double H) { Height = H; }
double __fastcall getHeight() const { return Height; }
double __fastcall Perimeter() const { return 2 * (Length + Height); }
double __fastcall Area() const { return Length * Height; }
TRectangle& operator=(const TRectangle& Rect);
private:
double Length;
double Height;
};
//---------------------------------------------------------------------------
#endif
|
The implementation of these functions also follows the same syntax applied to the addition operator:
//---------------------------------------------------------------------------
#pragma hdrstop
#include "Rectangle.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator=(const TRectangle& Rect)
{
Length = Rect.Length;
Height = Rect.Height;
return *this;
}
//---------------------------------------------------------------------------
TRectangle operator+(const TRectangle& x, const TRectangle& y)
{
TRectangle R;
R.Length = x.Length + y.Length;
R.Height = x.Height + y.Height;
return R;
}
//---------------------------------------------------------------------------
TRectangle operator-(const TRectangle& x, const TRectangle& y)
{
TRectangle R;
R.Length = x.Length - y.Length;
R.Height = x.Height - y.Height;
return R;
}
//---------------------------------------------------------------------------
TRectangle operator*(const TRectangle& x, const TRectangle& y)
{
TRectangle R;
R.Length = x.Length * y.Length;
R.Height = x.Height * y.Height;
return R;
}//---------------------------------------------------------------------------
TRectangle operator/(const TRectangle& x, const TRectangle& y)
{
TRectangle R;
if( y.Length == 0 ) // Avoid a zero denominator
R.Length = 0;
else
R.Length = x.Length / y.Length;
if( y.Height == 0 )
R.Height = 0;
else
R.Height = x.Height / y.Height;
return R;
}
//---------------------------------------------------------------------------
|
Adding a Constant to an Object |
|
Using integers or floating numbers, we are used to adding a constant to a variable, as in the following:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A = 1266.52;
double D;
D = A + 350.44;
cout << "Values of variables";
cout << "\nA = " << A;
cout << "\nD = " << D;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
Suppose that, instead of adding two objects, you decide to add a constant number to a class’ variable, as follows:
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect(42.88, 36.14);
TRectangle Plate = Rect + 32.84;
cout << "\n\nProperties of the plate";
Properties(Plate);
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
By overloading the addition operator, you can apply this operation to a variable declared from a class. To add a constant to the variable, you must create a version of the operator+() function that would take a constant and add it to the desired variable. After the operation is performed, the function must return a new variable that holds the new value (if the function does not return a value, the operation would be useless; you cannot display it on the console and you cannot assign the result to another variable). Therefore, the function would be declared as follows:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
friend TRectangle operator+(const TRectangle& x, const TRectangle& y);
public:
__fastcall TRectangle(double L = 0.00, double H = 0.00)
: Length(L), Height(H) {}
. . .
TRectangle& operator=(const TRectangle& Rect);
TRectangle& operator+(const double d);
private:
double Length;
double Height;
};
//---------------------------------------------------------------------------
#endif
|
The implementation of the function depends on what you are trying to achieve. For example, you can decide to add the constant value to only one member variable of the class. After performing the operation, the function must return the same variable on which it was applied, which is represented with the this pointer:
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator+(const double Number)
{
Length = Length + Number;
return *this;
}
//---------------------------------------------------------------------------
|
You can also add the constant argument to each member variable of the class:
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator+(const double Number)
{
Length = Length + Number;
Height = Height + Number;
return *this;
}
//---------------------------------------------------------------------------
|
Once the compiler knows how to add a constant to a variable declared from your class, you can use the operation the same way you would proceed for an integer or floating variable:
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect(42.88, 36.14), Recto(16.52, 22.65), CDCase;
CDCase = Recto + Rect;
cout << "Properties of the CD Case";
Properties(CDCase);
TRectangle Plate = Rect + 32.84;
cout << "\n\nProperties of the plate";
Properties(Plate);
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
The Sum Assignment Operator |
|
In the past we learned that one way to add a value to a variable is by using the sum assignment operator applied to the variable itself. Here is an example:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A = 1266.52;
double D = 560.25;
cout << "Values of variables";
cout << "\nA: " << A;
cout << "\nD: " << D;
A += 350.44;
cout << "\n\nAfter incrementing A, the values of variables are";
cout << "\nA: " << A;
cout << "\nD: " << D;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
The expression A += 350.44 is equivalent to A = A + 350.44. In other words, the constant value 350.44 is added to the variable A and renders the same variable A without the need of another variable. Besides adding a constant number to itself, a variable can also add the value of another variable of the same type to itself and thus modify the value it is holding. This is illustrated in the following:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A = 1266.52;
double D = 560.25;
cout << "Values of variables";
cout << "\nA: " << A;
cout << "\nD: " << D;
A += 350.44;
cout << "\n\nAfter incrementing A, the values of variables are";
cout << "\nA: " << A;
cout << "\nD: " << D;
A += D;
cout << "\n\nAfter self-adding D to A, the values of variables are";
cout << "\nA: " << A;
cout << "\nD: " << D;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
The += operation allows a variable to add a constant value to itself and change its (own) value after the operation. By default, this operation cannot be performed on a class. As we saw with adding a constant to a variable declared from a class, we can create our own version of the += operator to help the compiler figure out what to do when this operator is applied on our object.
The function used to perform this operation would look as follows:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
friend TRectangle operator+(const TRectangle& x, const TRectangle& y);
friend TRectangle operator-(const TRectangle& x, const TRectangle& y);
friend TRectangle operator*(const TRectangle& x, const TRectangle& y);
friend TRectangle operator/(const TRectangle& x, const TRectangle& y);
public:
. . .
TRectangle& operator=(const TRectangle& Rect);
TRectangle& operator+(const double d);
TRectangle& Adder(const TRectangle& x);
void operator+=();
private:
double Length;
double Height;
};
//---------------------------------------------------------------------------
#endif
|
The addition assignment operator “+=” works by assigning a value to a variable and hold a new value. The compiler will need to know what value is being added to the variable. Therefore, you must provide an argument that specifies this value. If this value is a variable of the same type that is being worked on, you must provide it by changing the function as:
void operator+=(TRectangle Rect);
The value of such an argument will not be modified in the function; it will only serve as the source of the value that is being added. For this reason, it should be passed as a constant. As long as it is not being modified, to speed up code execution, you should pass it as reference. The function would then change to:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
friend TRectangle operator+(const TRectangle& x, const TRectangle& y);
friend TRectangle operator-(const TRectangle& x, const TRectangle& y);
friend TRectangle operator*(const TRectangle& x, const TRectangle& y);
friend TRectangle operator/(const TRectangle& x, const TRectangle& y);
public:
. . .
TRectangle& operator=(const TRectangle& Rect);
TRectangle& operator+(const double d);
TRectangle& Adder(const TRectangle& x);
void operator+=(const TRectangle& Rect);
private:
double Length;
double Height;
};
//---------------------------------------------------------------------------
#endif
|
The implementation of this function simply consists, once more, of deciding what to add and what to leave out. For our example, we will add a member variable of the TRectangle variable that is making the call to the corresponding member variable of the argument:
//---------------------------------------------------------------------------
void TRectangle::operator+=(const TRectangle& R)
{
Length += R.Length;
Height += R.Height;
}
//---------------------------------------------------------------------------
|
After implementing this function, you can apply the += operator on a program as follows:
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect(42.88, 36.14), Recto(16.52, 22.65), Plate;
cout << "First Properties of Rect";
Properties(Rect);
Plate = Rect + 15.44;
cout << "\n\nAfter adding a constant to the rectangle";
Properties(Plate);
Rect += Recto;
cout << "\n\nSecond Properties of Rect";
Properties(Rect);
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
The += operator can also be applied by adding a constant value to the class variable that is making the call. The function can be declared as:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
. . .
public:
. . .
TRectangle& operator=(const TRectangle& Rect);
TRectangle& operator+(const double d);
TRectangle& Adder(const TRectangle& x);
void operator+=(const double d);
void operator+=(const TRectangle& Rect);
private:
double Length;
double Height;
};
//---------------------------------------------------------------------------
#endif
|
You can implement the function by deciding what member function would be modified. For this example, we will add the constant argument to each member variable of the class variable that is making the call:
//---------------------------------------------------------------------------
void TRectangle::operator+=(const double d)
{
Length += d;
Height += d;
}
//---------------------------------------------------------------------------
|
Once again, you can apply this operator once the compiler knows what to do with it. Here is an example:
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect(42.88, 36.14), Recto(16.52, 22.65), Plate;
cout << "First Properties of Rect";
Properties(Rect);
cout << "\n\nFirst call of the Plate rectangle";
Properties(Plate);
Plate += 15.44;
cout << "\n\nAfter adding a constant to the Plate rectangle";
Properties(Plate);
Rect += Recto;
cout << "\n\nSecond Properties of Rect";
Properties(Rect);
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
When the += operatotor is called by a variable, the value of the variable is modified. Because the += is a binary operator, it is forcefully applied on two value. After its execution, it results in a new value that can be assigned to another variable. Since a value is returned, it is safer to return a non-void value. The return value should be the same as the variable that made the call. This would change the function as follows:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
. . .
public:
. . .
TRectangle& operator=(const TRectangle& Rect);
TRectangle& operator+(const double d);
TRectangle& Adder(const TRectangle& x);
TRectangle operator+=(const double d);
TRectangle operator+=(const TRectangle& Rect);
private:
. . .
};
//---------------------------------------------------------------------------
#endif
|
Because the variable that makes the call also gets modified and preserves the newly acquired value, you can reinforce this by returning a reference instead of a regular object:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
. . .
public:
. . .
TRectangle& operator=(const TRectangle& Rect);
TRectangle& operator+(const double d);
TRectangle& Adder(const TRectangle& x);
TRectangle& operator+=(const double d);
TRectangle& operator+=(const TRectangle& Rect);
private:
. . .
};
//---------------------------------------------------------------------------
#endif
|
Now, the compiler expects the function to return a value. Since the variable that makes the call is also the same that is returned, the function should return the object that called it. This is done by returning the this pointer:
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator+=(const double d)
{
Length += d;
Height += d;
return *this;
}
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator+=(const TRectangle& R)
{
Length += R.Length;
Height += R.Height;
return *this;
}
//---------------------------------------------------------------------------
|
The other assignment operators can be declared as we did for the += operator:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
friend TRectangle operator+(const TRectangle& x, const TRectangle& y);
friend TRectangle operator-(const TRectangle& x, const TRectangle& y);
friend TRectangle operator*(const TRectangle& x, const TRectangle& y);
friend TRectangle operator/(const TRectangle& x, const TRectangle& y);
public:
__fastcall TRectangle(double L = 0.00, double H = 0.00);
__fastcall TRectangle(const TRectangle& R);
__fastcall ~TRectangle() {}
void __fastcall setLength(const double L) { Length = L; }
double getLength() const { return Length; }
void __fastcall setHeight(const double H) { Height = H; }
double __fastcall getHeight() const { return Height; }
void __fastcall setDimensions(const double L, const double H);
double __fastcall Perimeter() const { return 2 * (Length + Height); }
double __fastcall Area() const { return Length * Height; }
TRectangle& operator=(const TRectangle& Rect);
TRectangle& operator+(const double d);
TRectangle& Adder(const TRectangle& x);
TRectangle& operator+=(const double d);
TRectangle& operator+=(const TRectangle& Rect);
TRectangle& operator-=(const TRectangle& Rect);
TRectangle& operator*=(const TRectangle& Rect);
TRectangle& operator/=(const TRectangle& Rect);
private:
double Length;
double Height;
};
//---------------------------------------------------------------------------
#endif
|
The implementation also follows the same logic:
//---------------------------------------------------------------------------
#pragma hdrstop
#include "Rectangle.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
__fastcall TRectangle::TRectangle(double L, double H)
: Length(L), Height(H)
{
}
//---------------------------------------------------------------------------
__fastcall TRectangle::TRectangle(const TRectangle& R)
: Length(R.Length), Height(R.Height)
{
}
//---------------------------------------------------------------------------
void __fastcall TRectangle::setDimensions(const double L, const double H)
{
Length = L, Height = H;
}
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator=(const TRectangle& Rect)
{
Length = Rect.Length;
Height = Rect.Height;
return *this;
}
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator+(const double Number)
{
Length = Length + Number; return *this;
}
//---------------------------------------------------------------------------
TRectangle operator+(const TRectangle& x, const TRectangle& y)
{
TRectangle R;
R.Length = x.Length + y.Length;
R.Height = x.Height + y.Height;
return R;
}
//---------------------------------------------------------------------------
TRectangle operator-(const TRectangle& x, const TRectangle& y)
{
TRectangle R;
R.Length = x.Length - y.Length;
R.Height = x.Height - y.Height;
return R;
}
//---------------------------------------------------------------------------
TRectangle operator*(const TRectangle& x, const TRectangle& y)
{
TRectangle R;
R.Length = x.Length * y.Length;
R.Height = x.Height * y.Height;
return R;
}
//---------------------------------------------------------------------------
TRectangle operator/(const TRectangle& x, const TRectangle& y)
{
TRectangle R;
if( y.Length == 0 ) // Avoid a zero denominator
R.Length = 0;
else
R.Length = x.Length / y.Length;
if( y.Height == 0 )
R.Height = 0;
else
R.Height = x.Height / y.Height;
return R;
}
//---------------------------------------------------------------------------
TRectangle& TRectangle::Adder(const TRectangle& x)
{
Length = Length + x.Length;
Height = Height + x.Height;
return *this;
}
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator+=(const double d)
{
Length += d;
Height += d;
return *this;
}
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator+=(const TRectangle& R)
{
Length += R.Length;
Height += R.Height;
return *this;
}
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator-=(const TRectangle& R)
{
Length -= R.Length;
Height -= R.Height;
return *this;
}
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator*=(const TRectangle& R)
{
Length *= R.Length;
Height *= R.Height;
return *this;
}
//---------------------------------------------------------------------------
TRectangle& TRectangle::operator/=(const TRectangle& R)
{
if( R.Length == 0 )
Length = 0;
else
Length /= R.Length;
if( R.Height == 0 )
Height = 0;
else
Height /= R.Height;
return *this;
}
//---------------------------------------------------------------------------
|
The operators defined as such can appropriately be applied to the variables as needed:
//---------------------------------------------------------------------------
#include <iostream.h>
#include <iomanip.h>
#pragma hdrstop
#include "Rectangle.h"
//---------------------------------------------------------------------------
#pragma argsused
//---------------------------------------------------------------------------
void __fastcall Properties(const TRectangle& Rect)
{
cout << setiosflags(ios::fixed) << setprecision(2);
cout << "\nLength: " << Rect.getLength();
cout << "\nHeight: " << Rect.getHeight();
cout << "\nPerimeter: " << Rect.Perimeter();
cout << "\nArea: " << Rect.Area();
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect, Recto;
Rect.setDimensions(42.88, 36.14);
Recto.setDimensions(16.52, 22.65);
cout << "Using the += Operator";
Rect += Recto;
Properties(Rect);
Rect.setDimensions(42.88, 36.14);
Recto.setDimensions(16.52, 22.65);
cout << "\n\nUsing the -= Operator";
Rect -= Recto;
Properties(Rect);
Rect.setDimensions(42.88, 36.14);
Recto.setDimensions(16.52, 22.65);
cout << "\n\nUsing the *= Operator";
Rect *= Recto; Properties(Rect);
Rect.setDimensions(42.88, 36.14);
Recto.setDimensions(16.52, 22.65);
cout << "\n\nUsing the /= Operator";
Rect /= Recto;
Properties(Rect);
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
This would produce:
Using the += Operator
Length: 59.40
Height: 58.79
Perimeter: 236.38
Area: 3492.13
Using the -= Operator
Length: 26.36
Height: 13.49
Perimeter: 79.70
Area: 355.60
Using the *= Operator
Length: 708.38
Height: 818.57
Perimeter: 3053.90
Area: 579857.36
Using the /= Operator
Length: 2.60
Height: 1.60
Perimeter: 8.38
Area: 4.14
Press any key to continue...
|
Overloading Boolean Operators |
|
Boolean operators are used to compare the values held by two variables of a program. For example, the >= binary operator is used to find out whether one value is greater than another, as illustrated in the following main() function:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A = 1266.52;
double D = 560.25;
if( A >= D )
cout << "A is greater than D";
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
To perform this operation, the compiler examines the value of each variable. If the left variable has a value greater than that of the right variable, the comparison returns true; otherwise, the comparison returns false. This means a comparison opration is in fact a function that applies to two variables. Because the C++ compiler does not allow an overloaded operator to take two arguments, the function must be declared outside of the class. Since the function needs to have access to the private (or protected) members of the variables, it should be declared as a friend of the function. The data type common to Boolean operations and functions is bool and will be used to return the result of comparison functions:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
friend TRectangle operator+(const TRectangle& x, const TRectangle& y);
friend TRectangle operator-(const TRectangle& x, const TRectangle& y);
friend TRectangle operator*(const TRectangle& x, const TRectangle& y);
friend TRectangle operator/(const TRectangle& x, const TRectangle& y);
friend bool operator>=(const TRectangle& x, const TRectangle& y);
public:
. . .
private:
. . .
};
//---------------------------------------------------------------------------
|
Once again, the implementation of this function depends on the class or the intended result. For example, if the class is a square or any regular polygon, because its sides are equal, you can perform the comparison on the length of the sides:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
//---------------------------------------------------------------------------
struct TSquare
{
friend bool operator>=(const TSquare& q1, const TSquare& q2);
public:
__fastcall TSquare(double s = 0.00) : Side(s) {}
__fastcall TSquare(const TSquare& Q) : Side(Q.Side) {}
__fastcall ~TSquare() {}
void __fastcall setSide(const double s) { Side = s; }
double __fastcall getSide() const { return Side; }
double __fastcall Perimeter() const { return 4 * Side; }
double __fastcall Area() const { return Side * Side; }
TSquare& operator=(const TSquare& Q);
TSquare& operator+(const double Plus);
private:
double Side;
};
//---------------------------------------------------------------------------
bool operator>=(const TSquare& q1, const TSquare& q2)
{
if( q1.Side >= q2.Side )
return true; // Return true and exit from the function
return false; // If you get here, the comparison was not successful
}
//---------------------------------------------------------------------------
TSquare& TSquare::operator=(const TSquare& q)
{
Side = q.Side;
return *this;
}
//---------------------------------------------------------------------------
TSquare& TSquare::operator+(const double P)
{
Side = Side + P;
return *this;
}
//---------------------------------------------------------------------------
void __fastcall Properties(const TSquare& Carre)
{
cout << "\nSide: " << Carre.getSide();
cout << "\nPerimeter: " << Carre.Perimeter();
cout << "\nArea: " << Carre.Area();
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TSquare Square(24.08), Carre(15.36);
if( Square >= Carre )
cout << "Square is greater than Carre";
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
If the program consists of a restaurant menu, you can perform the comparison on the number of items ordered. If the classes are bank accounts, you can compare the balance on each account. In reality, every overloaded operator depends on your intentions and can be applied on one or more member variables and you can decide what validates the truthfulness of the comparison. For a geometric figure like the rectangle, we will compare the area of each rectangle. When the area of the left rectangle is greater than the area of the right rectangle, we will decide that the left rectangle if greater than the right rectangle:
//---------------------------------------------------------------------------
bool operator>=(const TRectangle& x, const TRectangle& y)
{
if( x.Area() >= y.Area() )
return true;
return false;
}
//---------------------------------------------------------------------------
|
With such an operator defined, you can compare two rectangles:
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect, Recto;
Rect.setDimensions(42.88, 36.14);
Recto.setDimensions(16.52, 22.65);
if( Rect >= Recto )
cout << "Rect is wider than Recto";
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
The other comparison operators can be overloaded following the same logic. For example, here are their declarations:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
friend TRectangle operator+(const TRectangle& x, const TRectangle& y);
friend TRectangle operator-(const TRectangle& x, const TRectangle& y);
friend TRectangle operator*(const TRectangle& x, const TRectangle& y);
friend TRectangle operator/(const TRectangle& x, const TRectangle& y);
friend bool operator==(const TRectangle& x, const TRectangle& y);
friend bool operator!=(const TRectangle& x, const TRectangle& y);
friend bool operator<(const TRectangle& x, const TRectangle& y);
friend bool operator<=(const TRectangle& x, const TRectangle& y);
friend bool operator>(const TRectangle& x, const TRectangle& y);
friend bool operator>=(const TRectangle& x, const TRectangle& y);
public:
. . .
private:
double Length;
double Height;
};
//---------------------------------------------------------------------------
#endif
|
Their implementations also follow the same logic applied to the += operator:
//---------------------------------------------------------------------------
#pragma hdrstop
#include "Rectangle.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
. . .
//---------------------------------------------------------------------------
bool operator==(const TRectangle& x, const TRectangle& y)
{
if( x.Area() == y.Area() )
return true;
return false;
}
//---------------------------------------------------------------------------
bool operator!=(const TRectangle& x, const TRectangle& y)
{
if( x.Area() != y.Area() )
return true;
return false;
}
//---------------------------------------------------------------------------
bool operator<(const TRectangle& x, const TRectangle& y)
{
if( x.Area() < y.Area() )
return true;
return false;
}
//---------------------------------------------------------------------------
bool operator<=(const TRectangle& x, const TRectangle& y)
{
if( x.Area() <= y.Area() )
return true;
return false;
}
//---------------------------------------------------------------------------
bool operator>(const TRectangle& x, const TRectangle& y)
{
if( x.Area() > y.Area() )
return true;
return false;
}
//---------------------------------------------------------------------------
bool operator>=(const TRectangle& x, const TRectangle& y)
{
if( x.Area() >= y.Area() )
return true;
return false;
}
//---------------------------------------------------------------------------
. . .
//---------------------------------------------------------------------------
|
This allows you to perform any comparison on variables declared from the class. Here is an example:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
#include "Rectangle.h"
//---------------------------------------------------------------------------
#pragma argsused
//---------------------------------------------------------------------------
void Properties(const TRectangle& Rect)
{
cout << "\nLength: " << Rect.getLength();
cout << "\nHeight: " << Rect.getHeight();
cout << "\nPerimeter: " << Rect.Perimeter();
cout << "\nArea: " << Rect.Area();
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect(42.88, 36.14), Recto(16.52, 22.65);
if( Rect != Recto )
cout << "Rect and Recto don't share the same size\n";
cout << "\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
The stream operators are used to either display items on the console or to request items from an external source.
Overloading the Output Operator |
|
The output operator “<<” is used to display data on the console screen. We have been using it as in the following example:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A = 1266.52;
double D = 560.25;
cout << "Values of the variables";
cout << "\nA: " << A;
cout << "\nD: " << D;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
As it does with regular variables, the compiler can be configured appropriately when the output operator is applied to a variable declared from a class. This makes it possible to write a statement such as:
TCountry Pais;
cout << Pais;
To appropriately display a variable on the console, you must overloaded the output << operator and tell the compiler how to behave when this operator is used on the variable. The function used to perform this operation is structured as operator<<(). Like any of the operators we have used so far, the compiler needs to know what variable is being worked on. Therefore, you must at least pass this variable as argument. When the output operator is executed, the intention is only to display the value(s) of the variable without modification. For this reason, the argument should be passed as a constant reference:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
. . .
public:
. . .
void operator<<(const TRectangle& Rect);
private:
. . .
};
//---------------------------------------------------------------------------
#endif
|
Any data display on the screen is managed by a class called ostream. This class communicates to the << operator how data must be displayed. Therefore, if you want to control how the compiler would display data, you must pass this class to your operator. Because the variable will be modified, in order to keep the modification performed on the variable, you should pass it as reference. This changes the function to:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
//---------------------------------------------------------------------------
class TRectangle
{
. . .
public:
. . .
void operator<<(ostream& Ostr, const TRectangle& Rect);
private:
. . .
};
//---------------------------------------------------------------------------
#endif
|
Since the ostream is an external class, make sure you include its header file, which is iostream.h. Now that the overloaded operator function is using two variables, it cannot be part of the class: you must declare it outside of the class. In order for the function to access private (and/or protected) member variables of the class, you should make it a friend of the class. The function becomes:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
#include <iostream.h>
//---------------------------------------------------------------------------
class TRectangle
{
friend void operator<<(ostream& Ostr, const TRectangle& Rect);
. . .
private:
. . .
};
//---------------------------------------------------------------------------
#endif
|
To implement this function, once again, tell the compiler what to do with it. You can access some members or each member variable of the class whose values you want to display and define how their values must be displayed. For this exercise, we will list the dimensions of the rectangle the way the corrdinates or a Cartesian point are displayed:
//---------------------------------------------------------------------------
void operator<<(ostream& Ostr, const TRectangle& R)
{
Ostr << "(" << R.Length << ", " << R.Height << ")";
}
//---------------------------------------------------------------------------
|
With the operator thus defined, the compiler knows how and what to display on the output operator. Here is an example of using it in a function:
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect(42.88, 36.14);
cout << "Rectangle: Rect";
cout << Rect;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
In practical terms, the output operator “<<” is a binary operator: it operates on two values. Consequently, it provides a result in the form of a third value. This means the operator<<() function should return a value. Because it is applied on the ostream class which allows it to tell the ostream class how to display data on the right side of the operator, the ostream argument is the one that gets modified and that is being worked on. The second argument, in this case the TRectangle is simply the source of data that will be displayed. Therefore, the function should return an instance of the ostream class. This means the function should be declared as follows:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
#include <iostream.h>
//---------------------------------------------------------------------------
class TRectangle
{
friend ostream& operator<<(ostream& Ostr, const TRectangle& Rect);
. . .
public:
. . .
private:
. . .
};
//---------------------------------------------------------------------------
#endif
|
This time, the function should return the result of the operation:
//---------------------------------------------------------------------------
ostream& operator<<(ostream& Ostr, const TRectangle& R)
{
Ostr << "(" << R.Length << ", " << R.Height << ")";
return Ostr;
}
//---------------------------------------------------------------------------
|
The input operator “>>” is used to request a value or some values from the user. Here is an example:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double A;
cout << "Type a double-precision number: ";
cin >> A;
cout << "\nThe value you typed is: " << A;
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
In the same way, you can write an overloaded version of the input operator. Its syntax would be: operator>>(). The class used to request values from the console is istream. To apply this operator, you should pass both an istream object and an instane of the class whose variables you want to request. Following the same logic applied to the output operator, the function would be declared as follows:
//---------------------------------------------------------------------------
#ifndef RectangleH
#define RectangleH
#include <iostream.h>
//---------------------------------------------------------------------------
class TRectangle
{
friend ostream& operator<<(ostream& Ostr, const TRectangle& Rect);
friend istream& operator>>(istream& Istr, TRectangle& Rect);
. . .
public:
. . .
private:
. . .
};
//---------------------------------------------------------------------------
#endif
|
When implementing this function, you will define how data input for the class will be processed, what to display and what to retrieve. Here is an example for our TRectangle class:
//---------------------------------------------------------------------------
istream& operator>>(istream& Istr, TRectangle& R)
{
cout << "Length: ";
Istr >> R.Length;
cout << "Height: ";
Istr >> R.Height;
return Istr;
}
//---------------------------------------------------------------------------
|
Now the cin >> operator can use an instance of your class the same way it would request the value of a regular variable. The cout and cin as defined can be called from any function. Here is an example:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
#include "Rectangle.h"
//---------------------------------------------------------------------------
#pragma argsused
//---------------------------------------------------------------------------
void __fastcall Properties(const TRectangle& R)
{
cout << R;
cout << "\nPerimeter: " << R.Perimeter();
cout << "\nArea: " << R.Area();
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TRectangle Rect;
cout << "Enter the dimensions of the rectangle\n";
cin >> Rect;
cout << "\nPropeties of the rectangle\n";
Properties(Rect);
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
|
|