exercise r14.1. to give an existing operator a new meaning ...€¦ · to give an existing operator...

20
Exercise R14.1. To give an existing operator a new meaning, what property must the argument types possess? Answer: When an operator is overloaded, it must perform special operations relative to the class which has been created. For example, a class that maintains a stack might overload ‘+’ to perform a push operation and ‘– ‘ to perform a pop. Hence, the argument type must not be a built-in data type for which the operator already works. Suppose, to give ‘+’ operator a new meaning, the arguments of the overloaded operator must not contain built-in data types like int, float, double, etc since for these data types, the addition operation is already defined by ‘+’ operator. The arguments of the overloaded operator must be objects of a user-defined class for which the addition ‘+’ operator is not defined. If a class named Location is created which has Latitude and Longitude as its member variables (integer).Two objects o1 and o2 of class Location are created, then addition operator must be overloaded so that it adds Latitude and Longitude of both the objects. Exercise R14.2. When would you choose an overloaded operator for a particular operation, and when would you choose a function? Answer: Operator is simply another way for you to make a function call. The difference is that the arguments for this function don’t appear inside parentheses, but instead they surround or are next to characters you’ve always thought of as immutable operators. There are two differences between the use of an operator and an ordinary function call. The syntax is different; an operator is often “called” by placing it between or sometimes after the arguments. The second difference is that the compiler determines which “function” to call. For instance, if you are using the operator + with floating- point arguments, the compiler “calls” the function to perform floating-point

Upload: vuxuyen

Post on 24-May-2018

221 views

Category:

Documents


0 download

TRANSCRIPT

Exercise R14.1. To give an existing operator a new meaning, what

property must the argument types possess?

Answer: When an operator is overloaded, it must perform special

operations relative to the class which has been created. For example, a

class that maintains a stack might overload ‘+’ to perform a push

operation and ‘– ‘ to perform a pop. Hence, the argument type must

not be a built-in data type for which the operator already works.

Suppose, to give ‘+’ operator a new meaning, the arguments of the

overloaded operator must not contain built-in data types like int, float,

double, etc since for these data types, the addition operation is already

defined by ‘+’ operator. The arguments of the overloaded operator

must be objects of a user-defined class for which the addition ‘+’

operator is not defined.

If a class named Location is created which has Latitude and Longitude

as its member variables (integer).Two objects o1 and o2 of class

Location are created, then addition operator must be overloaded so

that it adds Latitude and Longitude of both the objects.

Exercise R14.2. When would you choose an overloaded operator for a

particular operation, and when would you choose a function?

Answer: Operator is simply another way for you to make a function

call. The difference is that the arguments for this function don’t appear inside

parentheses, but instead they surround or are next to characters you’ve always

thought of as immutable operators. There are two differences between the use

of an operator and an ordinary function call. The syntax is different; an

operator is often “called” by placing it between or sometimes after the

arguments. The second difference is that the compiler determines which

“function” to call. For instance, if you are using the operator + with floating-

point arguments, the compiler “calls” the function to perform floating-point

addition (this “call” is typically the act of inserting in-line code, or a floating-

point-processor instruction). If you use operator + with a floating-point

number and an integer, the compiler “calls” a special function to turn

the int into a float, and then “calls” the floating-point addition code.

If we want to perform arithmetic operations on the objects of a class, then it is

essential to overload the operators( or use operator overloading functions).If

arithmetic operations are to be performed on the members of a class, then it is

necessary to define a member function to do the manipulation.

Exercise R14.3. Overload the + operator to raise an employee salary.

For example, harry + 5 gives Harry a 5 percent raise. Is this a good use

for operator overloading?

Answer: This is not a good use of operator overloading, since this

operation of raising the employee salary can be easily done with the

help of a function and there exists an overloaded ‘+=’ operator which

does the assignment and also performs the ‘+’ operation. However,

operator overloading can also be used but it is not necessary and is

redundant.

Exercise R14.5. When should an operator function be a member

function?

Answer: Each operator has its own considerations. For example, the <<

operator (when used for stream output, not bit shifting) gets an

ostream as its first parameter, so it can't be a member of your class. If

you're implementing the addition operator, you'll probably want to

benefit from automatic type conversions on both sides, therefore you'll

go with a non-member as well, etc...As for allowing specialization

through inheritance, a common pattern is to implement a non-member

operator in terms of a virtual member function (e.g. operator<< calls a

virtual function print() on the object being passed).

There are two situations under which operator overloading must be

done by functions that are not members of a specific class. These

situations are:-

1. The class to which the member function "should" be added is not available for modification. This frequently occurs with classes that are in standard class libraries. An example is the stream I/O library. 2. Type conversion of the arguments involved in the operation is desired.

Exercise R14.7. To print an object, access to the private data fields is

often necessary. Can the operator<< function be defined as a member

function to grant this access? If so, give an example. If not, explain why

not.

Answer:

Exercise R14.8. Why are there two versions of the ++ and -- operator

functions? Are there any other operators with two versions?

Answer: ‘++’ and ‘- -‘operators are increment and decrement

operators. They can either be pre-increment/post-increment or pre-

decrement/post-decrement. Hence, each (increment or decrement) has

its own variants (pre or post). When you write overloaded operator

functions, it can be useful to implement separate versions for the prefix

and postfix versions of these operators. To distinguish between the

two, the following rule is observed: The prefix form of the operator is

declared exactly the same way as any other unary operator; the postfix

form accepts an additional argument of type int.

For example:-

Operator++() and Operator- -() are pre-increment and pre-decrement

operators respectively,

Whereas, Operator++(int ) and Operator- -(int ) are post-increment and

post-decrement operators respectively.

Similarly, there exists two overloaded versions of the subscript ‘[]’

operator.

For example:-

const T& operator[](const int nIndex) const is a constant

method(function) ie it guarantees that it would not change any of the

class member variable(unless its mutable).It also returns a constant

object which means you can call only constant function i.e you can call

only functions that have const at the end similar to the one above

T& operator[](const int nIndex) This method may change the member

variables and returns an object that can call any class methods. We

need them both because the constant object would be using the

constant method and non-constant would be using the other one.

Exercise R14.9. Why should the prefix version of an increment operator

be used instead of the postfix version whenever you have a choice

between the two?

Answer:- Whenever in an assignment statement, a prefix version is

used the value of the object is incremented first and then assigned.

Whereas when a postfix version is used the value of the object is first

assigned and then the value of the object is incremented.

For example:- a=5;

int y= ++a;

a=5;

int x=a++;

In the above example, y will contain 6 while x will contain 5 this is

because in prefix, the value of a is incremented first and then it is

assigned to y while in postfix the value of a is first assigned to x and

then the value of a is incremented.

Hence, the prefix version of overloaded operator must be used instead

of a postfix version when the incremented value of an existing object

has to be assigned to a new object.

Exercise P14.1. Finish the implementation of the class Fraction by

overloading the remaining arithmetic operations.

Answer:

1. Addition operation a/b + c/d = (a*d + b*c)/(b*d)

Fraction operator+(const Fraction& left, const Fraction& right)

{

Fraction result(left.numerator() * right.denominator()

+ right.numerator() * left.denominator(),

left.denominator() * right.denominator());

return result;

}

2. Subtraction operation a/b - c/d = (a*d - b*c)/(b*d)

Fraction operator+(const Fraction& left, const Fraction& right)

{

Fraction result(left.numerator() * right.denominator()

- right.numerator() * left.denominator(),

left.denominator() * right.denominator());

return result;

}

3. Multiplication operation a/b * c/d = (a*c)/(b*d)

Fraction operator+(const Fraction& left, const Fraction& right)

{

Fraction result(left.numerator() * right.numerator(),

left.denominator() * right.denominator());

return result;

}

4.Division operation a/b / c/d =( a*d )/(b * c)

Fraction operator+(const Fraction& left, const Fraction& right)

{

Fraction result(left.numerator() * right.denominator(),

left.denominator() * right.numerator());

return result;

}

Exercise P14.5. Define a class Money, which maintains two integer data

fields, dollars and cents. Overload arithmetic operators, comparison

operators, and input and output operators for your class. Should you

overload the * and / operators? What argument types should they

accept? Overload the % operator so that if n is a floating-point value, n

% m yields n percent of the money amount m.

Answer:

Class Money

{

int dollar,cents;

public:

Money(int a, int b)

{

dollar=a;cents=b;

}

}

Operator overloading

1. Addition operator +

Money operator+(Money a)

{

int x, y;

y=cents+a.cents;

if(y>100)

{

y=y-100;

x=1;

}

x=x+dollar+a.dollar;

return Money(x,y)

}

2. Subtraction operator –

Money operator-(Money a)

{

int x,y;

cents>a.cents ? y=cents-a.cents : y=a.cents –cents;

dollar>a.dollar ? x=dollar-a.dollar : x=a.dollar –dollar;

if(cents <a.cents)

x=x-1;

return Money(x,y);

}

}

Comparison operators

Bool operator>(Money b)

{

if( (dollar + cents/100) > (b.dollar + b.cents/100))

return true;

else return false;

}

The operators ‘*’ and ‘/’ should can be overloaded and they must

accept float values as their arguments.

% operator

float Money∷operator%(float m, float n)

{

return (m *n / 100);

}

Exercise P14.6. Define a class Complex for complex numbers. Provide

implementations for addition, subtraction, multiplication, and the

stream input and output operators. Implement the compound

assignment operators for each of the sup- ported binary arithmetic

operations.

Answer:

class Complex

{

double real,imaginary; //member variables

public:

Complex(double x, double y)

{

real=x;imaginary=y;

}

Complex operator+(Complex a)

{

return Complex(real+a.real,imaginary+a.imaginary);

}

Complex operator-(Complex a)

{

return Complex(real-a.real,imaginary-a.imaginary);

}

Complex operator*(Complex a)

{

return Complex( real*a.real-

imaginary*a.imaginary,real*a.imaginary+a.real*imaginary);

}

Complex operator=+(Complex a)

{

real= real+a.real;

imaginary=imaginary+a.imaginary;

}

Complex operator=-(Complex a)

{

real= real-a.real;

imaginary=imaginary-a.imaginary;

}

Complex operator=*(Complex a)

{

real= real*a.real-imaginary*a.imaginary;

imaginary= real*a.imaginary+a.real*imaginary;

}

Exercise P14.7. Define a class BigInteger that stores arbitrarily large

integers by keeping their digits in a vector<int>. Supply a constructor

BigInteger(string) that reads a sequence of digits from a string.

Overload the +, -, and * operators to add, subtract, and multiply the

digit sequences. Overload the << operator to send the big integer to a

stream. For example,

BigInteger a("123456789");

BigInteger b("987654321");

cout << a * b;

prints 121932631112635269.

class BigInteger

{

Vector<int> digits;

BigInteger(char *s)

{

int i=0;

while(s[i]!=’\0’) { digits.pushback(s[i]-‘0’);i++;}

}

Overload ≪ operator

std::ostream& operator <<(std::ostream& out,BigInt a)

{

for(unsigned int i=0; i < a.digits.size(); i++){

out << a.digits[i] << endl;

}

return out;

}

Overload + operator

BigInt BigInt::operator +(BigInt a){

//BigInt temp;

int num = 0;

int carry = 0;

for(unsigned int i = 0; i < a.digits.size(); i++)

{

num = digits[i] + a.digits[i] + carry;

if(num >= 10)

{

num = num - 10;

carry = 1;

}

else{

carry = 0;

}

this->digits[i] = num;

}

if (carry){

this->digits.push_back(1);

}

return *this;

}

Overload – operator

Similar to + operator.

Exercise P14.8. Implement a class for polynomials. Store the coefficients in a vector of floating-point values. Then provide operators for addition, subtraction, multiplication, and output.

class Poly {

public:

Poly(int *p, int terms); // constructor

Poly operator + (Poly q); // poly addition

Poly operator - (Poly q); // poly subtraction

Poly operator * (Poly q); // poly multiplication

unsigned int deg() // degree { return(pol[0] > 0 ? pol[0] : 0); }

void display(); // display host object

/* other members */

private:

int length(); // length of pol

int * pol; };

Poly::Poly(int *p, int n) { // constructor

n = 2*n;

pol = new int[n+1];

for ( int i=0 ; i < n ; i++ )

pol[i] = *p++;

pol[n] = -1; }

#include <iostream>

#include "poly.h"

#define MAX(x,y) ((x) > (y) ? (x) : (y))

#define MIN(x,y) ((x) < (y) ? (x) : (y))

using namespace std;

Poly::Poly(int *p, int n) // constructor

{

n = 2*n;

pol = new int[n+1]; // dynamic allocation

for ( int i=0 ; i < n ; i++ )

pol[i] = *p++;

pol[n] = -1; // terminator

}

int Poly::length() // private member

{

int i;

for (i=0 ; pol[i] > -1 ; i += 2)

; // do nothing

return(i+1); }

Poly Poly::operator +(Poly q) {

int *c, *a, *b, *tmp;

unsigned len, d;

len = length()+q.length()-1;

d = 1 + 2*(1+ MAX(deg(), q.deg()));

len = MIN(len, d); // max length of answer

tmp = c = new(int[len]); // temporary space for result

a = pol; b = q.pol;

while (*a >= 0) // for each term of a

{

while(*b > *a) // terms in b of higher power

{

*c++ = *b++;

*c++ = *b++; }

*c++ = *a;

if (*a == *b) // add terms of like power

{

*c = *++a + *++b;

if (*c++ == 0) c -= 2; // terms cancel

b++;

}

else *c++ = *++a; // no terms to combine

a++;

}

while (*b >= 0) {

*c++ = *b++;

*c++ = *b++; } // add left over terms in b

*c = -1; // terminator marker

Poly ans(tmp, (c-tmp)/2); // answer object

delete tmp; // free temporary space

return(ans); }

void Poly::display() {

int *p = pol;

switch ( *p ) {

case -1: // zero poly

cout << "0" << endl; break;

case 0: // constant poly

cout << p[1] << endl; break;

default:

cout << '('; // display terms

while ( *p >= 0 ) {

cout << *p << " " << *(p+1);

p += 2;

if (*p != -1) cout << ", ";

}

cout << ")\n";

} // switch

}

#include "poly.h"

#include <iostream>

using namespace std;

int main(int argc, char * argv[]) {

int p1[] = { 3,5,0,4,-1};

int p2[] = { 3,2,1,4,-1};

Poly poly1(p1, 2); // create a two term Poly object p1

Poly poly2(p2, 2);

// we should have a display method to output the Polys

poly1.display(); // 5x^3 + 4

poly2.display(); // 2x^3 + 4x

poly1.displayNice(); // 5x^3 + 4

poly2.displayNice(); // 2x^3 + 4x

Poly poly3; // we need a default constructor too!

cout << "poly3 = ";

poly3.display();

// we should define a + () operator which returns a Poly

poly3 = poly1 + poly2;

poly3.display(); // 7x^3 + 4x + 4

Poly4 = poly3.deivative();

Poly4.display(); // 21x^2 + 4

// we should define a - () operator which returns a Poly

(poly1 + poly2).display(); } // 3x^3 4x + 4

Exercise P14.11. Can you make the class vector<double> act like the mathematical concept of a vector? Implement the addition operator so as to compute the vector sum of two vectors. Why might it be more efficient to implement += as an operator that computes the vector sum in place in the left argument? Measure the difference in speed between v += w and v= v + w.

Yes , class vector<double> can be used to implement a mathematical vector.

Class Vector

{

int n; //dimensions of the vector

vector<double> a;

public:

Vector(int I,double v[])

{

n=0;

while(n<i)

{

a[i]=v[i]; //copying the values of vector

i++;

}

}

Vector Vector∷operator+(Vector x)

{

int i=0;

Vector c;

while(i<a.size())

{

c.a[i]=x.a[i]+a[i];

i++;

}

Operator += is faster than + since += is an assignment as well as addition operator and it doesnot need to return any value whereas the ‘+’ operator performs addition and also returns and copies the result.