对于Complex类,最初觉得很容易。写下来之后,对照着大师的评论和实现,发现了差距,也理清了思路。在此贴出,以做参照。

/**//************************************************************************
The standard requires that operators = () [] and -> must be members, and
class-specific operators new, new[], delete, and delete[] must be static members.
For all other functions:

if the function is operator>> or operator<< for stream I/O,
or if it needs type conversions on its leftmost argument,
or if it can be implemented using the class's public interface alone,
make it a nonmember (and friend if needed in the first two cases)

if it needs to behave virtually,
add a virtual member function to provide the virtual behavior,
and implement it in terms of that

else
make it a member
************************************************************************/

#include <iostream>
using namespace std;

template <typename T>
class Complex

...{
template <typename Ty> friend class Complex;

public:
// In general it's a good idea to make your constructors explicit by default
// unless you deliberately decide to allow the implicit conversion
explicit Complex(T real, T imag = T()) : real_(real), imag_(imag)

...{
}

// Prefer writing "a op= b;" instead of "a = a op b;" (where op stands for any operator).
// It's clearer, and it's often more efficient
template <typename Ty>
Complex& operator +=(const Complex<Ty>& other)

...{
real_ += other.real_;
imag_ += other.imag_;
return *this;
}

template <typename Ty>
Complex& operator -=(const Complex<Ty>& other)

...{
real_ -= other.real_;
imag_ -= other.imag_;
return *this;
}

// Preincrement should return a reference to non-const梚n this case, Complex&.
// This lets client code operate more intuitively and avoids needless inefficiency.
Complex& operator ++()

...{
++real_;
return *this;
}

Complex& operator --()

...{
--real_;
return *this;
}

// Postincrement should return a const value in this case, const Complex.
// By not allowing changes to the returned object, we prevent questionable code like "a++++",
// which doesn't do what a naïve user might think it does.

// For consistency, always implement postincrement in terms of preincrement.
// Otherwise, your users will get surprising (and often unpleasant) results
const Complex operator ++(int)

...{
Complex temp(*this);
++*this;
return temp;
}

const Complex operator --(int)

...{
Complex temp(*this);
--*this;
return temp;
}

// Add a helper method to avoid friend methods for operator <<
// and if it is a base class, add virtual to print derived class
ostream& print(ostream& os) const

...{
return os << "(" << real_ << ", " << imag_ << ")";
}

private:
// follow the convention of designating member variable names with a trailing underscore
T real_, imag_;
};

// Notice the relationship between operators + and +=, - and -=.
// The former should be implemented in terms of the latter,
// both for simplicity (the code is easier to write) and
// for consistency (the two will do the same thing and
// are less likely to diverge during maintenance).
template <class T1, class T2>
const Complex<T1> operator +(const Complex<T1>& lhs, const Complex<T2>& rhs)

...{
Complex<T1> ret(lhs);
ret += rhs;
return ret;
}

template <class T1, class T2>
const Complex<T1> operator -(const Complex<T1>& lhs, const Complex<T2>& rhs)

...{
Complex<T1> ret(lhs);
ret -= rhs;
return ret;
}

// operator<< should not be a member function.
// operator<< should have a return type of "ostream&" and
// should return a reference to the stream in order to permit chaining.
// That way, users can use your operator<< naturally in code like "cout << a << b;".
template <class T>
ostream& operator <<(ostream& os, const Complex<T>& com)

...{
return com.print(os);
}

int main()

...{
Complex<double> c2(3, 4);
Complex<double> c3(0.1, 2.5);

cout << c2 << endl
<< c3 << endl
<< c3 + c2 << endl
<< c3 - c2 << endl;

return getchar();
}


























































































































































