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;
}