Thread: Class Templates

  1. #1
    Registered User
    Join Date
    Apr 2013
    Posts
    45

    Class Templates

    Hello, I need help with templates. I have been very confused with calling them in the main(). I understand the general idea of templates and overloading functions, but actually doing it in c++ is proving to be difficult. I think i called the constructor and copy constructor successfully so far. My main task is listed below, please help me accomplish this.

    Problem statement:
    Add a template to the arrayi.h class so that elements of the arrays can be integer, float or double. Also add a subtraction operator to the class.

    Task using the template implementations (in client_driver.cpp):
    Create arrays A1, A2 and A3. A1 is size 4 with elements 6 7 8 9 A2 is size 7.
    with elements 1 2 3 4 5 6 7. Assign A3 the difference of A1 and A2.


    //arrayi.h file (header file)

    Code:
    #ifndef ARRAYI_H_
    #define ARRAYI_H_
    
    #include <iostream>
    #include <cstdlib>
    #include <cassert>
    using namespace std;
    
    template<typename T>
    class Array;
    template<typename T>
    ostream &operator<< (ostream& output, const Array<T> &a);
    template<typename T>
    istream &operator>> (istream& input, Array<T> &a);
    
    template<typename T>
    class Array
      {
      public:
        Array(int = 10);    //constructor
        Array(const Array &);    //copy constructor
        ~Array();        //destructor
        int getSize() const;    //return size
        Array &operator = (const Array &);
        int operator==(const Array &) const;
        int operator != (const Array &) const;
        int &operator[] (int);
        Array operator + (const Array&);
        Array operator - (const Array&);
        static int getArrayCount();    //get count of existing
        //array objects
        friend ostream &operator<< <>(ostream &output, const Array<T> &a);
        friend istream &operator>> <>(istream &input, Array<T> &a);
    
      private:
        int *ptr;    //ptr to first array element
        int size;    //size of the array
        static int arrayCount;    // #of arrays instantiated
      };
    
    #include "arrayi.t"
    
    #endif
    //arrayi.t file (template implementations)

    Code:
    #include <iostream>
    #include <cstdlib>
    #include <cassert>
    using namespace std;
    
    
    // Initialize static data member at file scope
    template <typename T>
    T Array<T>::arrayCount = 0;   // no objects yet
    
    // Default constructor for class Array
    template <typename T>
    Array<T>::Array(int arraySize)
    {
      ++arrayCount;             // count one more object
      size = arraySize;        // default size is 10
      ptr = new int[size];      // create space for array
      assert(ptr != 0);  // terminate if memory not allocated
      int i;
      for (i = 0; i < size; i++)
        ptr[i] = 0;            // initialize array
    }
    
    // Copy constructor for class Array
    template <typename T>
    Array<T>::Array(const Array &init)
    {
      ++arrayCount;             // count one more object
      size = init.size;         // size this object
      ptr = new int[size];      // create space for array
      assert(ptr != 0);  // terminate if memory not allocated
      cout << "copy constr arrayi " << endl;
      int i;
      for (i = 0; i < size; i++)
        ptr[i] = init.ptr[i];  // copy init into object
      cout << endl << "copy constructor working" << endl;
    }
    
    // Destructor for class Array
    template <typename T>
    Array<T>::~Array()
    {
      --arrayCount;             // one fewer objects
      delete [] ptr;            // reclaim space for array
    }
    
    // Get the size of the array
    template <typename T>
    int Array<T>::getSize() const
      {
        return size;
      }
    
    // Overloaded assignment operator
    template <typename T>
    Array<T> &Array<T>::operator=(const Array &right)
    {
      if (&right != this)
        {    // check for self-assignment
          delete [] ptr;        // reclaim space
          size = right.size;    // resize this object
          ptr = new int[size];  // create space for array copy
          assert(ptr != 0);     // terminate if memory not allocated
          int i;
          for (i = 0; i < size; i++)
            ptr[i] = right.ptr[i];  // copy array into object
        }
      //this points to ptr to int,  *this returns ptr value
      //ie, the address of the array
      return *this;   // enables x = y = z;
    }
    // + operator for arrays
    template <typename T>
    Array<T>  Array<T>::operator + (const Array& right)
    {
      int large, small;
      if (size > right.size)
        {
          large = size;
          small = right.size;
        }
      else
        {
          large = right.size;
          small = size;
        }
      Array z(large);
      int i;
      for (i = 0; i < small; i++)
        z.ptr[i] =   ptr[i] + right.ptr[i];
      for (i = small; i < large; i++)
        {
          if (right.size == small)
            z.ptr[i] =   ptr[i] ;
          else  z.ptr[i] =   right.ptr[i] ;
        }
      cout << "# of arrays instantiated " << getArrayCount() << endl;
      return z;
    }
    
    // Determine if two arrays are equal and
    // return 1 if true, 0 if false.
    template <typename T>
    int Array<T>::operator==(const Array &right) const
      {
        if (size != right.size)
          return 0;    // arrays of different sizes
        int i;
        for (i = 0; i < size; i++)
          if (ptr[i] != right.ptr[i])
            return 0; // arrays are not equal
    
        return 1;       // arrays are equal
      }
    
    // Determine if two arrays are not equal and
    // return 1 if true, 0 if false.
    template <typename T>
    int Array<T>::operator!=(const Array &right) const
      {
        if (size != right.size)
          return 1;         // arrays of different sizes
        int i;
        for (i = 0; i < size; i++)
          if (ptr[i] != right.ptr[i])
            return 1;      // arrays are not equal
    
        return 0;            // arrays are equal
      }
    
    // Overloaded subscript operator
    template <typename T>
    int &Array<T>::operator[](int subscript)
    {
      // check for subscript out of range error
      assert(0 <= subscript && subscript < size);
      return ptr[subscript];   // reference return creates lvalue
    }
    
    // Return the number of Array objects instantiated
    template <typename T>
    int Array<T>::getArrayCount()
    {
      return arrayCount;
    }
    
    // Overloaded input operator for class Array;
    // inputs values for entire array.
    template <typename T>
    istream &operator>>(istream &input, Array<T> &a)
    {
      int i;
      for (i = 0; i < a.size; i++)
        input >> a.ptr[i];
    
      return input;   // enables cin >> x >> y;
    }
    
    // Overloaded output operator for class Array
    template <typename T>
    ostream &operator<<(ostream &output, const Array<T> &a)
    {
      int i;
      for (i = 0; i < a.size; i++)
        {
          output << a.ptr[i] << ' ';
    
          if ((i + 1) % 10 == 0)
            output << endl;
        }  //end for
    
      if (i % 10 != 0)
        output << endl;
    
      return output;   // enables cout << x << y;
    }
    //arrayi.cpp

    Code:
    #include "arrayi.h"
    //client_driver.cpp

    Code:
    #include "arrayi.h"
    #include <iostream>
    #include <cstdlib>
    #include <cassert>
    using namespace std;
    
    
    int main()
    {
        Array<int> intObject;                       //call constructor
        Array<int> intObjectCopy(intObject);  //call copy constructor
       
        //rest of code here
    }

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    To do what you're asked, there needs to be some facility so your main() function can add elements of type T to the array. There is none.

    Try to work out what you need to do to the Array class so that this would work
    Code:
    //   header files, etc
    
    int main()
    {
          Array<int> A1;
    
          A1.AppendElement(6);
          A1.AppendElement(7);
    }
    would work.

    I've chosen to name the operation AppendElement() but you can name it as anything you like.

    Also:; big hint. Look at the operator[] function.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #3
    Registered User
    Join Date
    Apr 2013
    Posts
    45
    Quote Originally Posted by grumpy View Post
    To do what you're asked, there needs to be some facility so your main() function can add elements of type T to the array. There is none.

    Try to work out what you need to do to the Array class so that this would work
    Code:
    //   header files, etc
    
    int main()
    {
          Array<int> A1;
    
          A1.AppendElement(6);
          A1.AppendElement(7);
    }
    would work.

    I've chosen to name the operation AppendElement() but you can name it as anything you like.

    Also:; big hint. Look at the operator[] function.


    Thanks for the response.
    There's something in the class I have to change?
    Right now, I'm not sure as to what.
    Why could I name the operation anything I want; don't I have to use A1 to access a member of the class?

  4. #4
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by thomann061 View Post
    There's something in the class I have to change?
    Yes.

    I've already given you two hints about two possible changes (adding a member function, or changing the specification of an existing member function). There are other types of change you might consider.

    I'm not going to be more specific than that - this is your homework, not mine.

    Generally, speaking, you need to consider how the specification of an Array<int> would need to differ from an Array<double>. At the least, I would expect an Array<double> to have one or more members with arguments or return type that are double, not int.

    Quote Originally Posted by thomann061 View Post
    Why could I name the operation anything I want; don't I have to use A1 to access a member of the class?
    As I said, one change you might make to the class is to create an additional member function that provides additional capability.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  5. #5
    Registered User
    Join Date
    Apr 2013
    Posts
    45
    Quote Originally Posted by grumpy View Post
    Yes.

    I've already given you two hints about two possible changes (adding a member function, or changing the specification of an existing member function). There are other types of change you might consider.

    I'm not going to be more specific than that - this is your homework, not mine.

    Generally, speaking, you need to consider how the specification of an Array<int> would need to differ from an Array<double>. At the least, I would expect an Array<double> to have one or more members with arguments or return type that are double, not int.



    As I said, one change you might make to the class is to create an additional member function that provides additional capability.
    New code:

    // arrayi.t

    Code:
    #ifndef ARRAYI_H_
    #define ARRAYI_H_
    
    #include <iostream>
    #include <cstdlib>
    #include <cassert>
    using namespace std;
    
    template<typename T>
    class Array;
    template<typename T>
    ostream &operator<< (ostream& output, const Array<T> &a);
    template<typename T>
    istream &operator>> (istream& input, Array<T> &a);
    
    template<typename T>
    class Array
      {
    
      public:
        Array(T = 10);    //constructor
        Array(const Array<T> &);    //copy constructor
        ~Array();        //destructor
        T getSize() const;    //return size
        Array<T> &operator = (const Array<T> &);
        T operator==(const Array<T> &) const;
        T operator != (const Array<T> &) const;
        T &operator[] (T);
        Array<T> operator + (const Array<T>&);
        Array<T> operator - (const Array<T>&);
        static T getArrayCount();    //get count of existing
        //array objects
        friend ostream &operator<< <>(ostream &output, const Array<T> &a);
        friend istream &operator>> <>(istream &input, Array<T> &a);
    
      private:
        T *ptr;    //ptr to first array element
        T size;    //size of the array
        static T arrayCount;    // #of arrays instantiated
      };
    
    #include "arrayi.t"
    
    #endif
    // arrayi.t

    Code:
    #include <iostream>
    #include <cstdlib>
    #include <cassert>
    using namespace std;
    
    
    // Initialize static data member at file scope
    template <typename T>
    T Array<T>::arrayCount = 0;   // no objects yet
    
    // Default constructor for class Array
    template <typename T>
    Array<T>::Array(T arraySize)
    {
      ++arrayCount;             // count one more object
      size = arraySize;        // default size is 10
      ptr = new T[size];      // create space for array
      assert(ptr != 0);  // terminate if memory not allocated
      T i;
      for (i = 0; i < size; i++)
        ptr[i] = 0;            // initialize array
    }
    
    // Copy constructor for class Array
    template <typename T>
    Array<T>::Array(const Array<T> &init)
    {
      ++arrayCount;             // count one more object
      size = init.size;         // size this object
      ptr = new T[size];      // create space for array
      assert(ptr != 0);  // terminate if memory not allocated
      cout << "copy constr arrayi " << endl;
      int i;
      for (i = 0; i < size; i++)
        ptr[i] = init.ptr[i];  // copy init into object
      cout << endl << "copy constructor working" << endl;
    }
    
    // Destructor for class Array
    template <typename T>
    Array<T>::~Array()
    {
      --arrayCount;             // one fewer objects
      delete [] ptr;            // reclaim space for array
    }
    
    // Get the size of the array
    template <typename T>
    T Array<T>::getSize() const
      {
        return size;
      }
    
    // Overloaded assignment operator
    template <typename T>
    Array<T> &Array<T>::operator=(const Array<T> &right)
    {
      if (&right != this)
        {    // check for self-assignment
          delete [] ptr;        // reclaim space
          size = right.size;    // resize this object
          ptr = new T[size];  // create space for array copy
          assert(ptr != 0);     // terminate if memory not allocated
          int i;
          for (i = 0; i < size; i++)
            ptr[i] = right.ptr[i];  // copy array into object
        }
      //this points to ptr to int,  *this returns ptr value
      //ie, the address of the array
      return *this;   // enables x = y = z;
    }
    // + operator for arrays
    template <typename T>
    Array<T>  Array<T>::operator + (const Array<T> &right)
    {
      int large, small;
      if (size > right.size)
        {
          large = size;
          small = right.size;
        }
      else
        {
          large = right.size;
          small = size;
        }
      Array z(large);
      int i;
      for (i = 0; i < small; i++)
        z.ptr[i] =   ptr[i] + right.ptr[i];
      for (i = small; i < large; i++)
        {
          if (right.size == small)
            z.ptr[i] =   ptr[i] ;
          else  z.ptr[i] =   right.ptr[i] ;
        }
      cout << "# of arrays instantiated " << getArrayCount() << endl;
      return z;
    }
    
    // - operator for arrays
    template <typename T>
    Array<T>  Array<T>::operator - (const Array<T> &right)
    {
      int large, small;
      if (size > right.size)
        {
          large = size;
          small = right.size;
        }
      else
        {
          large = right.size;
          small = size;
        }
      Array z(large);
      int i;
      for (i = 0; i < small; i++)
        z.ptr[i] =   ptr[i] - right.ptr[i];
      for (i = small; i < large; i++)
        {
          if (right.size == small)
            z.ptr[i] =   ptr[i] ;
          else  z.ptr[i] =   right.ptr[i] ;
        }
      cout << "# of arrays instantiated " << getArrayCount() << endl;
      return z;
    }
    
    // Determine if two arrays are equal and
    // return 1 if true, 0 if false.
    template <typename T>
    T Array<T>::operator==(const Array<T> &right) const
      {
        if (size != right.size)
          return 0;    // arrays of different sizes
        int i;
        for (i = 0; i < size; i++)
          if (ptr[i] != right.ptr[i])
            return 0; // arrays are not equal
    
        return 1;       // arrays are equal
      }
    
    // Determine if two arrays are not equal and
    // return 1 if true, 0 if false.
    template <typename T>
    T Array<T>::operator!=(const Array<T> &right) const
      {
        if (size != right.size)
          return 1;         // arrays of different sizes
        int i;
        for (i = 0; i < size; i++)
          if (ptr[i] != right.ptr[i])
            return 1;      // arrays are not equal
    
        return 0;            // arrays are equal
      }
    
    // Overloaded subscript operator
    template <typename T>
    T &Array<T>::operator[](T subscript)
    {
      // check for subscript out of range error
      assert(0 <= subscript && subscript < size);
      return ptr[subscript];   // reference return creates lvalue
    }
    
    // Return the number of Array objects instantiated
    template <typename T>
    T Array<T>::getArrayCount()
    {
      return arrayCount;
    }
    
    // Overloaded input operator for class Array;
    // inputs values for entire array.
    template <typename T>
    istream &operator>>(istream &input, Array<T> &a)
    {
      int i;
      for (i = 0; i < a.size; i++)
        input >> a.ptr[i];
    
      return input;   // enables cin >> x >> y;
    }
    
    // Overloaded output operator for class Array
    template <typename T>
    ostream &operator<<(ostream &output, const Array<T> &a)
    {
      int i;
      for (i = 0; i < a.size; i++)
        {
          output << a.ptr[i] << ' ';
    
          if ((i + 1) % 10 == 0)
            output << endl;
        }  //end for
    
      if (i % 10 != 0)
        output << endl;
    
      return output;   // enables cout << x << y;
    }
    // client_driver

    Code:
    #include "arrayi.h"
    
    #include <iostream>
    #include <cstdlib>
    #include <cassert>
    using namespace std;
    
    
    int main()
    {
        Array<int> A1(4);
        Array<int> A2(7);
        Array<int> A3;
        A1.getSize();
        A1.getArrayCount();
        cout << "Enter values for first array: ";
        cin >> A1;
        cout << "Enter values for second array: ";
        cin >> A2;
        cout << "Difference of first and second array: ";
        A3 = A2 - A1;
        cout << A3;
    }
    After posting my new code, things are becoming more clear. Have I accomplished my task successfully? I am unsure whether I would need to use the [], ==, and != operators for. Are they there just in case I need to use them? Also, I am unsure why I would need to called the member class functions getSize() and getArrayCount.

    Thank you guys, you are the best!

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    You've over-corrected now.

    The size of an array of double (or of anything) is generally an integral value. Similarly, comparison operators (==, !=, etc) generally yield an integral result.

    You need to be clear whether the argument to an Array constructor represents the initial size (which will be an integral value) or the value of an element (which will be double for an Array<double>, int for an Array<int>).

    In short, you need to actually think about what the various members and member functions stand for.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  7. #7
    Registered User
    Join Date
    Apr 2013
    Posts
    45
    Quote Originally Posted by grumpy View Post
    You've over-corrected now.

    The size of an array of double (or of anything) is generally an integral value. Similarly, comparison operators (==, !=, etc) generally yield an integral result.

    You need to be clear whether the argument to an Array constructor represents the initial size (which will be an integral value) or the value of an element (which will be double for an Array<double>, int for an Array<int>).

    In short, you need to actually think about what the various members and member functions stand for.
    Okay, I understand. I will change them back.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Class templates
    By SterlingM in forum C++ Programming
    Replies: 1
    Last Post: 01-09-2010, 09:11 PM
  2. New to class templates
    By lisa1901 in forum C++ Programming
    Replies: 10
    Last Post: 10-02-2007, 04:23 PM
  3. Class Templates Again
    By creativeinspira in forum C++ Programming
    Replies: 9
    Last Post: 07-01-2007, 05:13 AM
  4. class templates...
    By Anddos in forum C++ Programming
    Replies: 1
    Last Post: 03-17-2006, 09:30 PM
  5. class templates
    By tygernoot in forum C++ Programming
    Replies: 2
    Last Post: 11-21-2004, 10:26 AM