operator=
ob1 = ob2;) works as you would
expect: each member¤ of ob1 is assigned to the
corresponding member¤ of ob2
Coefficient c (0.5);
// AND LATER...
c = 0.75;
Coefficient::SetValue(double) member¤ function
already does the job:
class Coefficient
{
public:
Coefficient(double initVal)
{ myValue = initVal; myAccesses = 0; }
double GetValue(void) const
{ myAccesses++; return myValue; }
bool SetValue(double v)
{
myAccesses++;
if (v<0 || v>1) { return false; }
myValue = v;
return true;
}
private:
double myValue;
mutable int myAccesses;
};
Coefficient c (0.5);
// AND LATER...
c.SetValue(0.75);
c = val) actually call c.SetValue(val)
operator=
operator<symbol>
operator=.
Coefficient::SetVal to Coefficient::operator=
we get the desired effect:
class Coefficient
{
public:
Coefficient(double initVal)
{ myValue = initVal; myAccesses = 0; }
double GetValue(void) const
{ myAccesses++; return myValue; }
bool operator= (double v)
{
myAccesses++;
if (v<0 || v>1) { return false; }
myValue = v;
return true;
}
private:
double myValue;
mutable int myAccesses;
};
Coefficient c (0.5);
// AND LATER...
c = 0.75; // ACTUALLY CALLS: c.operator=(0.75);
Coefficient:
class Coefficient
{
public:
// ...AS BEFORE...
bool operator+=(double addval)
{ return addValue(addval); }
bool operator-=(double subval)
{ return addValue(-subval); }
private:
bool addValue(double v)
{
myAccesses++;
if (myVal+addval<0 || myVal+addval>1)
return false;
myValue += v;
return true;
}
};
class Coefficient
{
public:
// ...AS BEFORE...
bool operator= (double v)
{
myAccesses++;
if (v<0 || v>1)
return false;
myValue = v;
return true;
}
bool operator= (char* str)
{
if (!strcmp(str,"default"))
return operator=(0.5);
else if (!strcmp(str, "max")
return operator=(0.0);
else if (!strcmp(str, "min"))
return operator=(1.0);
else
return false;
}
private:
// ...AS BEFORE...
};
Coefficient c(0.6);
c = 0.75;
c = "max";
c = "default";
<var> <op> <value> into
<var>.operator<op>(<value>),
there's a major problem if we want to overload an operator
where the first operand isn't a class¤ type.
Coefficient
objects together (producing new Coefficient objects). We
could write:
class Coefficient
{
public:
// ...AS BEFORE...
Coefficient operator+ (Coefficient c)
{
Coefficient sum (this->myValue + c.myValue);
return sum;
}
Coefficient operator+ (double d)
{
Coefficient sum (this->myValue + d);
return sum;
}
private:
// ...AS BEFORE...
};
Coefficient c1 (0.25);
Coefficient c2 (0.45);
Coefficient c3 (0.5);
c3 = c1 + c2; // REALLY: c3.operator=(c1.operator+(c2));
// CALLS: Coefficient::operator+(Coefficient)
c3 = c1 + 0.4; // REALLY: c3.operator=(c1.operator+(0.4));
// CALLS: Coefficient::operator+(double)
// BUT NOT...
c3 = 0.4 + c1; // CAN'T CALL (0.4).operator+(c1) !!!
Coefficient add(double leftval, Coefficient rightval)
{
Coefficient leftValAsCoeff (leftval);
return leftValAsCoefficient + rightVal;
}
operator<op> name:
Coefficient operator+ (double leftval, Coefficient rightval)
{
Coefficient leftValAsCoeff (leftval);
return leftValAsCoefficient + rightVal;
}
<var> <op> <value>, the compiler
does the following:<var> is of an inbuilt type
(int, char*, etc.), the standard (inbuilt) operator is used
<var> is of a user-defined class¤
type (Coefficient, Vehicle,
etc.), the compiler checks if there is a suitable user-defined operator<op>
function defined (that is, one whose parameter is of the same type as
<value>, or of a type convertable to
the type of <value>). If so, that function
is used class Complex
{
public:
Complex(float re, float im)
: myReal(re), myImag(im)
{}
Complex operator+(Complex c)
{
Complex sum(myReal+c.myReal, myImag+c.myImag);
return sum;
}
Complex operator+(double re)
{
Complex sum(myReal+re, myImag);
return sum;
}
Complex operator+(int re)
{
Complex sum(myReal+re, myImag);
return sum;
}
float Real(void)
{ return myReal; }
float Imag(void)
{ return myImag; }
private:
float myReal;
float myImag;
};
Complex operator+(Complex c1, Complex c2)
{
Complex sum(c1.Real()+c2.Real(), c1.Imag()+c2.Imag());
return sum;
}
Complex operator+(double d, Complex c2)
{
Complex sum(d+c2.Real(), c2.Imag());
return sum;
}
Complex c1 (1.1, 0);
Complex c2 (9,9. 9);
double d (1.1);
int i (0);
char c ('c');
c1 + d; // CALL Complex::operator+(double)
d + c1; // CALL ::operator+(double,Complex)
c1 + i; // CALL Complex::operator+(int)
i + c1; // CALL ::operator+(double,Complex)
c1 + c; // AMBIGOUS: Complex::operator+(double)
// OR: Complex::operator+(int)
// EQUALLY GOOD (1 CONVERSION EACH)
c + c1; // CALL ::operator+(double,Complex)
c1 + c2; // AMBIGOUS: Complex::operator+(Complex)
// OR: ::operator+(Complex,Complex)
// EQUALLY GOOD (NO CONVERSION FOR EITHER)
operator+ functions for the
Complex class¤ we had to rely on calls to
Complex::Real() and Complex::Imag(). Why?
Complex that those non-member¤ functions really do
"belong" to the class¤ (in the ADT sense), and therefore
should have access to the private members¤ of class¤ objects.
friend keyword
to declare that a particular non-member¤ function has
unrestricted access to a class¤:
class Complex
{
// DECLARE THE SPECIFIED GLOBAL FUNCTION AS A FRIEND
// OF THIS CLASS...
friend Complex operator+(double, Complex);
public:
Complex(float re, float im)
: myReal(re), myImag(im)
{}
// ETC. ETC. AS BEFORE...
};
Complex operator+(double d, Complex c2)
{
// CAN NOW ACCESS PRIVATE MEMBERS OF c2...
Complex sum(d+c2.myReal, c2.myImag);
return sum;
}
+ - * & ~ ! ++ -- -> ->*
+ - * / % ^ & | << >> += -= *= /= %= ^= &= |= <<= >>= < <= > >= == != && || , [] () new new[] delete delete[]
. .* ?: ::
^ or binary
!, for example)
= << >>
Complex,
Matrix, Vector, etc.) then the full range of
(valid!) arithmetic operations on the type should
also be offered
<< and >>,
we can allow user-defined classes¤ to perform I/O just
like inbuilt types (!)
#include <iostream.h>
class Complex
{
public:
Complex(float re, float im)
: myReal(re), myImag(im)
{}
friend istream& operator>>(istream&, Complex&);
friend ostream& operator<<(ostream&, const Complex&);
private:
float myReal;
float myImag;
};
istream& operator>>(istream& in, Complex& c)
{
double real, imag;
in >> real >> imag;
if (in.good())
{
c.myReal = real;
c.myImag = imag;
}
return in;
}
ostream& operator<<(ostream& out, const Complex& c)
{
out << "(" << c.myReal << "," << c.myImag << ")";
return out;
}