next up previous
Next: The C++ standard complex Up: canned_classes Previous: canned_classes


Templates: mycomplex.h

We have seen how to construct simple classes to handle complex numbers and vectors. In both cases we chose to make the components double precision. If we later decided to work with single precision complex numbers, we would have to rewrite the class definition. If we wanted both precisions to coexist in the same calculation, we would need a separate name for each class.

Through the ``template'' feature C++ saves us the tedium of rewriting the class definitions. Here is how it works for the simplest version of mycomplex.h.



#include <iostream>
using namespace std;

template<class T>
class complex {
public:
  T re;
  T im;
};

int main(){
   complex<double> a;

   cout << "Enter Re and Im\n";
   cin >> a.re >> a.im;
   cout << "Your number is " << a.re << " + I * " << a.im << "\n";
}


Notice the new prefix to the class declaration:

template<class T>

The word class in the angle brackets here is apt to be confusing, because it has nothing to do with the classes we have been discussing so far. It is just the way we signal to the compiler that the label T is a substitution parameter that stands for any datatype we might want to use later on to complete the definition. Notice that T appears twice in the class declaration.


The template is invoked when we use it. In the main program we see the declaration:

   complex<double> a;

The name of the class has a suffix <double> which causes double to replace every occurrence of T in the template declaration. If, later on, we wanted to create a single precision complex number, we could do it this way:
   complex<float> b;
The same template is used, but now with float replacing T. Note, however, we can no longer say, simply, complex c;. A suffix is always required.

If we tire of always writing complex<double> and complex<float>, we can create abbreviated names using a typedef statement as follows:

   typedef complex<double> dcmplx;
   typedef complex<float>  fcmplx;
Then we can declare variables by their shortened type names as follows:
   dcmplx a;
   fcmplx b;
The general form for the typedef statement is
   typedef oldname newname;
These statements are usually collected at the top of the source file along with the #include directives, or better still, they are collected in header files.

Templates can also be used with function definitions. For example, the cadd function that adds two complex numbers was defined with the double precision complex type in mind. We can generalize its definition as follows:




#include <iostream>
using namespace std;

template<class T>
class complex {
public:
  T re;
  T im;
  
  // Constructors
  complex<T>(){re = 0; im = 0;}
  complex<T>(T r, T i = 0){re = r; im = i;}
};

template<class FLT>
complex<FLT> cadd(complex<FLT> &z1, complex<FLT> &z2)
{
  return complex<FLT>(z1.re + z2.re, z1.im + z2.im);
}

The function cadd has been templatized. For variety we used the parameter FLT this time, but even if we had used T again, it would not be confused with the same label used in the class declaration above.

Here is how we use this class and this function.




typedef complex<double> dcmplx;
typedef complex<float>  fcmplx;

int main(){
  dcmplx a, b, sum;
  
  cout << "Enter Re(a) and Im(a)\n";
  cin >> a.re >> a.im;
  cout << "Enter Re(b) and Im(b)\n";
  cin >> b.re >> b.im;
  sum = cadd(a, b);
  cout << "a + b is " << sum.re << " + I * " << sum.im << "\n";
}

Notice, also that the cadd function call in the main program


  sum = cadd(a, b);

does not require a suffix <double>. The compiler can tell which version of cadd we intend by looking at the arguments. They are both of type complex<double>, so it concludes that we must have intended to replace T with double in the function template to match the required function signature.


next up previous
Next: The C++ standard complex Up: canned_classes Previous: canned_classes
Carleton DeTar 2008-11-10