Looks like I'm late to the party, since, apparently, at the very least your original problem was solved, and there also seems to be plenty of advice in that context and in fact a wide scope around it.
What I was missing though after skimming over the various responses (but I may have skipped it), was a word of advice on the declaration and use of arithmetic operators. Others already pointed out the danger of implicit conversion operators, but what I think they failed to mention is that arithmetic operators, too, can cause unwanted conversions.
Consider the following:
class Integer {
int Value;
public:
Integer(int v=0) : Value(v) {}
Integer(const Integer& v) : Value(v.Value) {}
Integer& operator=(const Integer& v) { Value = v.Value; return *this; }
int operator+=(const Integer& v) { Value += v.Value; return Value; }
friend int operator+(const Integer& v1, const Integer& v2);
friend int operator-(const Integer& v1, const Integer& v2);
friend int operator*(const Integer& v1, const Integer& v2);
friend int operator/(const Integer& v1, const Integer& v2);
};
void foo() {
Integer a(3), b(5), c(7), d(11);
Integer e = (a+b)*(c-d); Integer f = (b+=13)/(c+=d); }
(1) this line will first invoke
int operator+(const Integer& v1, const Integer& v2)
and
int operator-(const Integer& v1, const Integer& v2)
, and then construct
e
using
Integer(int v)
. Since the result of the first two operators are both int, the multiplication will not invoke
int operator*(const Integer& v1, const Integer& v2)
.
(2) Similarly, this line will invoke
Integer(int v=0)
to convert
13
to
Integer
, then invoke
int operator+=(const Integer& v)
twice, and finally use
Integer(int v=0)
to construct
f
. Again, the result type of
operator+=(...)
prevents the invocation of
int operator/(const Integer& v1, const Integer& v2)
.
Now, if you want to implement some behaviour in Integer that is different from int (and there would be no point if that wasn't your intention), then you may want to control the results of multiplications and divisions just as you do additions and substractions. But, by declaring the result types as int, you implicitely convert intermediate results of your arithmetic operations to int, preventing the use of your own operators.
What you have to do instead is return objects or references to your class, for any operator where it makes sense. You can always add an
explicit conversion back to int when you need it - but not before:
class Integer {
int Value;
public:
Integer(int v=0) : Value(v) {}
Integer(const Integer& v) : Value(v.Value) {}
explicit operator int() const { return Value; } Integer& operator=(const Integer& v) { Value = v.Value; return *this; }
Integer& operator+=(const Integer& v) { Value += v.Value; return *this; }
friend Integer operator+(const Integer& v1, const Integer& v2);
friend Integer operator-(const Integer& v1, const Integer& v2);
friend Integer operator*(const Integer& v1, const Integer& v2);
friend Integer operator/(const Integer& v1, const Integer& v2);
};
void foo() {
Integer a(3), b(5), c(7), d(11);
Integer e = (a+b)*(c-d); Integer f = (b+=13)/(c+=d); int g = (int)f; }
Now your
operator*(...)
and
operator/(...)
will be called, since the intermediate results are of type
Integer
.
Note that the result type of
operator+=(...)
is a reference! This saves you (or the runtime system) the effort of creating a temporary that you otherwise would need as an argument for
operator/(...)
(3) Also note that I added the keyword
explicit
to the conversion operator to prevent unwanted implicit conversion. Now, if you want to convert an
Integer
to an
int
, you have to explicitely cast it. That should serve your purpose, but is a cleaner and safer way to do it.
(4) A belated note regarding my suggested use of
explicit
(thanks to Andreas Gieriet for pointing this out):
Using the keyword
explicit
on conversion operators is a new feature of C++11. Not all compilers support it (certainly not the older versions).