C++ classes can be feature-rich, complex and powerful
We have function overloading by means of difference of function's signatures
We can overload operators as well
The same principal follows: "one kind of operator can have many forms"
Actually, some operators in C++ are already overloaded
The operator '*'. If it applies to an address, it yields the value stored at that address (de-reference)
If applies to numbers, it multiplies the numbers
The operator '<<' will print out number, char or string
When apply to C++ objects, we want to have the following:
// Instead of using for (int i = 0; i < 20; i++) evening[i] = carmen[i] + richard[i]; // Add element by element // We can have a class defined (with internal data structure an array couple = carmen + richard;
To overload an operator, we have to use a special function call "operator"
operatorop(argument-list)
Where op is the symbol for the operator being overloaded, op must be a valid operator in C++
E.g. operator+ function would overload the + operator
E.g
If richard, carmen, couple are objects of Peoples class, then we can writecouple = richard + carmen;
Or recognizing the operands as belonging to the Peoples class, we can rewrite it to:
couple = richard.operator+(carmen);
const Stock land = Stock("IBM")
land.show(); // This will fail, because show does not guarantee that // it won't modify the invoking object. And show has no // parameter, so there is no trick we can play in the parameter listSo, C++ allows that we use the const keyword after the function declaration
Example:
void show() const; // promises not to change invoking objectvoid stock::show() const // promises not to change invoking objectWe called these functions: const member functions
Our first example: A vector, used in engineering and physic a lot, is a quantity having both a magnitude (size) and a direction
Example:
// vector0.h -- vector class before operator overloading #ifndef _VECTOR0_H_ #define _VECTOR0_H_ class Vector { private: double x; // horizontal value double y; // vertical value double mag; // length of vector double ang; // direction of vector void set_mag(void); void set_ang(void); public: Vector(void); Vector(double h, double v); // set x, y values ~Vector(void); void set_by_polar(double m, double a); double xval() const {return x;} // report x value double yval() const {return y;} // report y value double magval() const {return mag;} // report magnitude double angval() const {return ang;} // report angle void show_polar(void) const; // show polar values void show_vector(void) const ; // show rectangular values }; #endif
// Let's Overload the + operator by adding the following Vector operator+(const Vector & b) const; // prototype Vector Vector::operator+(const Vector & b) const // definition { double sx, sy; sx = x + b.x; // x component of sum sy = y + b.y; // y component of sum Vector sum = Vector(sx, sy); return sum; }We pass the parameter by reference to save memory and performance timeThe function should not alter the value of the vectors it is adding, we declare the argument as a const type and declare the function a const method// When using, we can use eitherVector q = move1.operator+(move2); // function call syntaxVector q = move1 + move2; // alternative syntax
More example in the demo/lab
C++ controls access to the private portions of a class object (by the use of private and public sessions)
Usually only public class methods serve as the only access
Might be too rigid to fit particular programming problems ... So we have 'friends'
Friends can be:
- Friend functions
- Friend classes
- Friend member functions
By making a function a friend to a class, you allow the function the same access privileges that a member function of the class has
Often overloading a binary operator (a operator with two arguments) for a class generates a need for friends
For example:
// Continue with our vector example, let's overload the * operator // So, if you much a vector by 3, all the component within the vector will // get multiple by 3Vector operator*(double n) const; // prototype// Multiplies invoking vector by n Vector Vector::operator*(double n) const // definition { double mx, my; mx = n * x; my = n * y; Vector mult = Vector(mx, my); return mult; }
// The code works fine as follow:Vector v1 = myvect * 2.0; // valid code // Or in alternative form Vector v1 = myvect.operator*(2.0);The above function require that operator*() be a member function of the Vector class AND the function takes a type double arugment
But ... what about this:
Vector v1 = 2.0 * myvect; // Not support// Because Vector v1 = 2.0.operator*(myvect); // Is nonsenseActually, we really need a function that looks like this:
Vector operator*(double n, const Vector &a);
So, 2.0 * myvector will be
operator*(2.0, myvector);
We can do this by making friends :)
A friend function is a nonmember function that is allowed access to an object's private section
Use the friend keyword
Example:
friend Vector operator*(double n, const Vector & a); // Nonmember friendVector operator*(double n, const Vector & a) { return a * n; }// Now, this is supported Vector v1 = 2.0 * myvect;In General, if you want to overload an operator for a class and you want to use the operator with a nonclass term as the first operand, you have to use a friend function to reverse the operand order.
Both Friend and Operator Overloading are "Good and Bad" features in C++
Operator Overloading makes the object operations much compact and relatively easier to code
However, once operators are overloaded, code maintance becomes more expensive. For example, + now can be applied to multiple different objects and all the implementation is internal ... it might be a nightmare for someone to change or update the existing code.
Friend, on the other hand, breaks the donut concept we have. Data encapsulation can be broken by friend functions.
Good OO design should avoid friend to ensure data encapsulation
However, friend will be your good friend when you are doing performance enhancement or quick bug fix.
Note: both of these features are not present in Java
Sequence.hpp (class definition)