8.
Operators and
enumerated types
8.3.Overloaded operators in detail
The number of arguments
of the operator you want
to overload
1 2
The way the as a global 1 2
operator is (standalone)
implemented function
as a class 1 1
member function
8.3.3 What you mustn’t do
• define new operators
• change the priority
• overload operators working with standard data
types.
8.3.4 Arithmetic operators
#include <iostream>
using namespace std; 8.3.4 Arithmetic operators
class V {
public:
float vec[2];
V(float a0, float a1) { vec[0]=a0; vec[1]=a1; }
V operator+(V &arg) {
V res(0.0f,0.0f);
for(int i = 0; i < 2; i++)
res.vec[i] = vec[i] + arg.vec[i];
return res; int main(void) {
V v1(0.0f, 1.0f), v2(1.0f, 0.0f), v3(0.0f, 0.0f);
} float x;
}; v3 = v1 + v2;
float operator*(V &left, V &right) { x = v1 * v2;
cout << "(" << v3.vec[0] << ", " << v3.vec[1] << ")" << endl;
float res = 0.0; cout << x << endl;
for(int i = 0; i < 2; i++)
}
return 0; (1, 1)
res += left.vec[i] * right.vec[i];
0
return res;
}
8.3.5 Bitwise operators
#include <iostream>
using namespace std;
8.3.5 Bitwise operators
class V {
public:
int vec[2];
V(int a0, int a1) { vec[0]=a0; vec[1]=a1; }
V operator>>(int arg) {
V res(vec[0],vec[1]);
for(int i = 0; i < 2; i++)
res.vec[i] >>= arg;
return res; int main(void) {
V v(15, 7);
} v = v >> 1;
}; cout << "(" << v.vec[0] << ", " << v.vec[1] << ")" << endl;
cout << ~v << endl;
int operator~(V &arg) { return 0;
int res = 1; } (7, 3)
for(int i = 0; i < 2; i++) 21
res *= arg.vec[i];
return res;
}
8.3.6 Assignment operator
8.3.6 Assignment operator
int main(void) {
V v1(4, 8), v2, v3;
#include <iostream> v2 = v3 = v1;
using namespace std; cout << "(" << v2.vec[0] << ", " << v2.vec[1] << ")" << endl;
class V { return 0;
public: }
int vec[2];
V(int a0, int a1) { vec[0]=a0; vec[1]=a1; }
V(void) { vec[0]=vec[1]=0; }
V& operator=(V &arg) {
for(int i = 0; i < 2; i++) The example here shows an
vec[i] = arg.vec[1 - i]; assignment which swaps the
return *this; vector being assigned: not very
useful and not rather funny,
} but very illustrative.
};
int main(void) {
V v1(4, 8), v2;
v2 = v1;
cout << "(" << v2.vec[0] << ", " << v2.vec[1] << ")" << endl;
return 0;
}
8.3.7 Relational operators
8.3.7 Relational operators
#include <iostream>
using namespace std;
class V {
public:
int vec[2];
V(int a0, int a1) { vec[0]=a0; vec[1]=a1; } int main(void) {
V v1(4, 8), v2(3, 7);
bool operator==(V &arg) { cout << (v1 == v2 ? "true" : "false") << endl;
for(int i = 0; i < 2; i++) cout << (v1 > v2 ? "true" : "false") << endl;
return 0;
if(vec[i] != arg.vec[i]) }
return false;
return true;
}
};
bool operator>(V &l, V &r) {
return l.vec[0]+l.vec[1] > r.vec[0]+r.vec[1];
}
8.3.8 Logical operators
8.3.8 Logical operators
#include <iostream>
#include <cmath>
using namespace std;
class V {
public:
int vec[2];
int main(void) {
V(int a0, int a1) { vec[0]=a0; vec[1]=a1; } V v1(4, 8), v2(3, 7);
bool operator&&(V &arg) { cout << (v1 && v2 ? "true" : "false") << endl;
cout << (!v1 ? "true" : "false") << endl;
return abs(vec[0]) + abs(vec[1]) > 0 && return 0;
abs(arg.vec[0]) + abs(arg.vec[1]) > 0; }
}
};
bool operator!(V &v) {
return v.vec[0] * v.vec[1] != 0;
}
8.3.9 Compound assignment operators
#include <iostream> 8.3.9 Compound assignment operators
using namespace std;
class V {
public:
int vec[2];
V(int a0, int a1) { vec[0]=a0; vec[1]=a1; }
V& operator+=(V &arg) {
for(int i = 0; i < 2; i++)
vec[i] += arg.vec[i]; int main(void) {
return *this; V v1(0, 0), v2(1, 2), v3(3, 4);
v1 = v2 + v3;
} v1 += v1;
}; cout << "(" << v1.vec[0] << ", " << v1.vec[1] << ")" << endl;
V& operator+(V &left, V &right) { return 0;
V *res = new V(0, 0); }
for(int i = 0; i < 2; i++)
res->vec[i] = left.vec[i] + right.vec[i]; (8, 12)
return *res;
}
la syntaxe d’implémentation de l'opérateur de
surcharge
Opérateurs d’incrémentation, décrémentation :
nomclasse operator++ ( ) ; pour le type préfixé
nomclasse operator++ (int) ; pour le type postfixé
nomclasse operator--() ; pour le type préfixé
nomclasse operator--(int) ; pour le type postfixé
8.3.10 Prefix increment and decrement operators
#include <iostream>
using namespace std;
8.3.10 Prefix increment and
class V { decrement operators
public:
int vec[2];
V(int a0, int a1) { vec[0]=a0; vec[1]=a1; }
V& operator++(void) {
for(int i = 0; i < 2; i++)
vec[i]++;
return *this;
}
}; (2, 3)
int main(void) {
V v1(1, 2);
++v1;
cout << "(" << v1.vec[0] << ", " << v1.vec[1] << ")" << endl;
return 0;
}
8.3.11 Postfix increment and decrement
operators
Operators ++ --
May be implemented as NO
global function?
May be implemented as a YES
member function?
Type of return value A reference to an object or
an l-value in general
#include <iostream>
using namespace std;
class V { 8.3.11 Postfix increment
public:
int vec[2]; and decrement operators
V(int a0, int a1) { vec[0]=a0; vec[1]=a1; }
V operator++(int none) {
V v(vec[0],vec[1]);
for(int i = 0; i < 2; i++)
++vec[i];
return v;
}
};
int main(void) {
V v1(2, 3);
v1++;
cout << "(" << v1.vec[0] << ", " << v1.vec[1] << ")" << endl;
return 0; }
8.4 Overloaded operators in detail
(continued)
8.4.1 Subscript
operator
#include <iostream>
#include <stdexcept>
using namespace std;
8.4.1 Subscript operator
class Arr {
int main(void) {
private: Arr arr;
int a, b, c, d; for(int i = 1; i <= 4; i++)
public: arr[i] = i * i;
Arr() { a = b = c = d = 0; } for(int i = 4; i > 0; i--)
cout << arr[i] << endl;
int& operator[] (int index) { return 0;
switch(index) { }
case 1: return a;
case 2: return b;
case 3: return c;
case 4: return d;
default: throw range_error("bad index");
}
}
};
8.4.2 Function invocation operator
#include <iostream> 8.4.2 Function invocation
using namespace std;
class Fun {
public:
operator
int operator() (int a1, int a2) {
return a1 > a2 ? a1 : a2;
}
int operator() (int a1, int a2, int a3) {
return a1 > a2 ? (a1 > a3 ? a1 : a3) : (a2 > a3 ? a2 : a3);
}
}; The function invocation operator is very different. Here are some of its
characteristics:
int main(void) { • the number of its parameters isn’t predefined; you can use as
Fun f; many parameters as you want.
• the return type is neither predefined nor suggested; use the
one you need.
cout << f(1,2) << endl; • one class may contain more than one overloaded
cout << f(1,2,3) << endl; operator () function; specify as many as you need, but
return 0; remember to keep them all distinguishable by the number and
} types of parameters (relate it to the requirements for overloaded
functions).
The operator may be used to create objects that pretend to be functions.
The example program shows this type of imitating class. It overloads the () operator twice to create a guise for two
overloaded functions, finding a maximal of their arguments.
8.4.3 Pointer operators
8.4.3 Pointer operators
#include <iostream> P& operator*(string s) {
#include <string> P *p;
using namespace std; if(!s.compare("alpha"))
class P { p = new P(0);
public: else if(!s.compare("bravo"))
int no; p = new P(1);
P(int n) : no(n) { } else if(!s.compare("charlie"))
P() : no(0) { } p = new P(2);
string operator&() { else
switch(no) { p = new P(-1);
case 0: return "alpha"; return *p; The & operator overloaded inside the P class
case 1: return "bravo"; } creates a new “pointer”, representing an object
with the selected no field value, while the
case 2: return
int main(void) { overloaded * operator creates a new object
"charlie"; based on the dereferenced “pointer”
} P p1(2);
(string actually) value.
} string s = &p1;
}; P p2 = *s;
cout << "'" << s << "' -> " << p2.no << endl;
return 0;
}
8.4.4 Other overloadable operators
All the
operators listed here,
are overloadable in the “C++” language.
Operator ,
Operators →
Operator new
operator new[]
operator delete
operator delete[]
operator typename
The operators listed here, are non-
overloadable in the “C++” language.
?:
.
::
sizeof
8.4.6 Fraction – a class with overloaded
operators
#ifndef __FRACTION_H__
#define __FRACTION_H__
#include <stdexcept>
#include <string>
fraction.h
class Fraction {
private:
int numerator, denominator;
int LCM(int x, int y); Note:
int GCD(int x, int y); • LCM is short for Lowest Common Multiplier
public: • GCD is short of Greatest Common Divisor
Fraction(); • a function converting a fraction into a string is called GetString
• a function converting a fraction into a double value is called GetValue
Fraction(int n);
Fraction(int n,int d) throw(std::domain_error);
std::string GetString(void); The implementations of the LCM
double GetValue(void); and GDM algorithms are classic
Fraction operator!(void);
Fraction operator+(Fraction arg);
Fraction operator*(Fraction arg);
Fraction operator/(Fraction arg) throw(std::domain_error);
Fraction& operator+=(Fraction arg);
};
std::ostream& operator<< (std::ostream &ostr, Fraction &f);
#endif
#include <iostream>
#include <sstream>
Fraction.cpp 1/3
#include "fraction.h"
using namespace std;
int Fraction::LCM(int x, int y) {
int i = y; Fraction::Fraction() : numerator(0), denominator(1) {}
while(y % x) Fraction::Fraction(int n) : numerator(n), denominator(1) {}
y += i;
return y; Fraction::Fraction(int n,int d) throw(domain_error) :
} numerator(n), denominator(d) {
int Fraction::GCD(int x, int y) { if(denominator == 0)
for(;;) { throw domain_error("bad fraction");
x %= y; }
if(!x) string Fraction::GetString(void) {
return y; ostringstream os;
y %= x; os << "[" << numerator << "/" << denominator << "]";
if(!y) return os.str();
return x; }
}
}
double Fraction::GetValue(void) {
}
return double(numerator) / double(denominator);
Fraction.cp2/3
Fraction Fraction::operator!(void) {
int gcd = GCD(numerator, denominator);
return Fraction(numerator / gcd, denominator / gcd);
p
}
Fraction Fraction::operator+(Fraction arg) {
int common_denom = LCM(denominator, arg.denominator);
int numera = numerator * common_denom / denominator +
arg.numerator * common_denom / arg.denominator;
Fraction f(numera, common_denom);
return f;
}
Fraction Fraction::operator*(Fraction arg) {
int numera = numerator * arg.numerator;
int denomi = denominator * arg.denominator;
Fraction f(numera, denomi);
return !f;
}
Fraction Fraction::operator/(Fraction arg) throw(domain_error) {
if(arg.numerator == 0)
throw domain_error("division by zero");
int numera = numerator * arg.denominator;
int denomi = denominator * arg.numerator;
Fraction.c 3/3
Fraction f(numera, denomi);
return !f;
pp
}
Fraction& Fraction::operator+=(Fraction arg) {
int common_denom = LCM(denominator, arg.denominator);
int numera = numerator * common_denom / denominator +
arg.numerator * common_denom / arg.denominator;
numerator = numera;
denominator = common_denom;
return *this;
}
ostream& operator<< (ostream &ostr, Fraction &f) {
return ostr << f.GetString();
}
#include "fraction.h"
#include "fraction.cpp"
tester.c
#include <iostream>
using namespace std; pp
int main(void) {
Fraction f1(1,2), f2(2,3), f;
cout << f1 << "->" << f1.GetValue() << endl;
cout << f2 << "->" << f2.GetValue() << endl;
f = f1 + f2;
cout << f1 << "+" << f2 << "=" << f << endl;
f = f2 + f2 + f2;
cout << f2 << "+" << f2 << "+" << f2 << "=" << f << endl;
f = !f;
cout << f2 << "+" << f2 << "+" << f2 << "=" << f << endl;
f = f1 * f2;
cout << f1 << "*" << f2 << "=" << f << endl;
f = f1 / f2;
cout << f1 << ":" << f2 << "=" << f << endl;
Fraction f3(7,8);
f3 += f1;
cout << f3 << endl;
return 0;
}
SURCHARGE DES OPERATEURS
D'ENTRÉE-SORTIE
• Les opérateurs d'insertion >> et d’extraction << dans le flux,
aussi appelés opérateurs d’entrée-sortie, sont très souvent
surchargés par les développeurs qui leur confèrent alors une
personnalisation adaptée aux traitements en cours.
• Cette opération de surcharge va devoir utiliser des classes
existantes au sein du fichier d’en-tête iostream, qui sont
ostream pour l’extraction de flux et istream pour l’insertion.
• Les paramètres d’entrée comme la valeur de retour seront
passés par référence. Ces opérateurs surchargés seront des
fonctions amies.
ostream& operator<< (ostream& ostr, const classe1 a);
istream& operator>> (istream& istr, const classe1 a);
Assessments chap 8 Operators and
enumerated types
#include <iostream>
using namespace std; Q1
class Int {
public:
int v;
Int(int a) { v = a; } Select correct answer (single choice)
• It prints 2
}; • It prints 0
• It prints 1
int main() { • Compilation fails
Int i = 1;
cout << i;
return 0;
}
#include <iostream>
using namespace std; Q2
class Int {
public:
int v;
Int(int a) { v = a; }
}; Select correct answer (single choice)
ostream & operator <<(Int•&a)It prints
{ 1
• It prints 2
return cout << a.v; • It prints 0
} • Compilation fails
int main() { Rappel
Int i = 1;
cout << i;
#include <iostream>
using namespace std; Q3
class Int {
public:
int v;
Int(int a) { v = a; }
};
ostream &operator <<(ostream &o,correct
Select Int answer (single choice)
&a) { • It prints 0
return o << --a.v; • It prints 2
• It prints 1
} • Compilation fails
int main() {
Int i = 1;
#include <iostream> ostream &operator <<(ostream &o, Int &a) {
a.v++;
using namespace std; return o << a.v; Q
class Int { } 4
public: int main() {
Int i = 0;
int v; --i ; i--;
Int(int a) { v = a; } cout << i << i;
Int &operator--() { return 0;
}
++v; Select correct answer (single choice)
return *this; • It prints 10
• It prints 23
} • Compilation fails
Int &operator--(int v) { • It prints 21
v+=2;
return *this;
#include ostream &operator <<(ostream &o, Int &a) {
<iostream> }
return o << a.v;
Q5
using namespace int main() {
std; Int i = 0;
i++;
class Int { cout << i << i.v;
public: return 0;
int v; }
Int(int a) { v = a; } Select correct answer (single choice)
• It prints 20
Int • Compilation fails
&operator++(int x) • It prints 22
{ • It prints 21
v+=2;
return *this;
#include <iostream>
using namespace std;
class Int { Q6
public:
int v;
Int(int a) { v = a; }
Int &operator[](int x) {
v+=x;
return *this;
}
};
ostream &operator <<(ostream
&o, Int &a) {
return o << a.v; Select correct answers (multiple choice)
}
int main() { • It prints 24
Int i = 2; • Compilation fails
cout << i.v ; • It prints 33
cout << i[2];
return 0; • It prints 22
}
#include <iostream>
using namespace std; Q7
enum T { A = 2, B = -1, C };
class Int {
public:
T v;
Int(T a) { v = a; }
Int & operator++() { v = C; return
*this; }
};
ostream &operator <<(ostream
&o, Int &a) { Select correct answer (single choice)
++a; • It prints C
return o << a.v; • It prints 1
} • It prints 0
int main() { • Compilation fails
Int i = B;
cout << i;
return 0;
}
#include <iostream>
using namespace std;
enum T { A = 2, B = -1, C }; Q8
class Int {
public:
T v;
Int(T a) { v = a; }
Int & operator++() { v += 2;
return *this; }
};
ostream &operator <<(ostream
&o, Int &a) {
++a; Select correct answer (single choice)
return o << a.v; • It prints 0
} • Compilation fails
int main() { • It prints 1
Int i = B; • It prints 2
cout << i;
return 0;
}
#include <iostream>
using namespace std;
class N {
Q9
public:
float x;
N() { x = 0.0; }
N(float a) { x = a; }
N(N &n) { x = n.x; }
N &operator=(float f) { x = f - 1; return
*this; }
}; Select correct answer (single choice)
int main() { • It prints 0
N a; • It prints 2
a = 2.0; • It prints 1
cout << a.x; • Compilation fails
return 0;
}
#include <iostream>
#include <string> Q1
using namespace std;
class N { 0
public:
float x;
N() { x = 0.0; }
N(float a) { x = a; }
N(N &n) { x = n.x; }
string operator==(float f) { if(int(x) == int(f)) return "true";
else return "false"; }
};
int main() { Select correct answer (single choice)
N a(1.1); • Compilation fails
cout << (a == 1.9); • It prints an empty string
return 0; • It prints false
} • It prints true
Fin