I am trying to create a function that counts the number of each DNA part (A, C, T, and G) that are entered by a user into an ADT that stores data in an array. I am having trouble because I keep getting the error "error C2955: 'List' : use of class template requires template argument list". Any help would be appreciated. The function I need help with is countBases in the first file. Below are my files:

Code:
//--------------------------------------------------------------------
//
//  Laboratory 3, In-lab Exercise 1                     test3dna.cpp
//
//  Test program for the countbases function
//
//--------------------------------------------------------------------

// Reads a DNA sequence from the keyboard, calls function countBases
// countBases (which uses a list to represent a DNA sequence), and
// outputs the number of times that each base (A, G, C and T) occurs
// in the sequence.

#include <iostream>
#include "ListArray.cpp"

using namespace std;

//--------------------------------------------------------------------
//
//  Function prototype
//

void countBases ( List<char> &dnaSequence,
                  int &aCount,
                  int &cCount,
                  int &tCount,
                  int &gCount              );

//--------------------------------------------------------------------


int main ()
{
    List<char> dnaSequence(25);   // DNA sequence (25 bases max.)
    char base;              // DNA base
    int aCount,             // Number of A's in the sequence
        cCount,             // Number of C's in the sequence
        tCount,             // Number of T's in the sequence
        gCount;             // Number of G's in the sequence

    // Read the DNA sequence from the keyboard.

    cout << endl << "Enter a DNA sequence: ";
    cin.get(base);
    while ( base != '\n' )
    {
        dnaSequence.insert(base);
        cin.get(base);
    }

    // Display the sequence.

    cout << "Sequence: ";

    if( dnaSequence.isEmpty() )
       cout << "list is empty" << endl;
    else
    {
       dnaSequence.gotoBeginning();
       do
       {
         cout << dnaSequence.getCursor() << " ";
       } while ( dnaSequence.gotoNext() );
       cout << endl;
    }

    // Count the number of times that each base occurs.

    countBases(dnaSequence,aCount,cCount,tCount,gCount);

    // Output the totals.

    cout << "Number of A's : " << aCount << endl;
    cout << "Number of C's : " << cCount << endl;
    cout << "Number of T's : " << tCount << endl;
    cout << "Number of G's : " << gCount << endl;

}

//--------------------------------------------------------------------
//
//  Insert your countBases function below.
//

template < typename DataType >
void countBases (List& dnaSequence, int& aCount, int& cCount, int& tCount, int& gCount)
{
	for(int i = 0; i < 25; i++)
	{
		if(dnaSequence.getCursor() == 'a')
			aCount++;
		if(dnaSequence.getCursor() == 'c')
			cCount++;
		if(dnaSequence.getCursor() == 't')
			tCount++;
		if(dnaSequence.getCursor() == 'g')
			gCount++;

		dnaSequence.gotoNext();
	}
}
Code:
//--------------------------------------------------------------------
//
//  Laboratory 3                                           ListArray.h
//  **Instructor's Solution**
//  Class declaration for the array implementation of the List ADT
//
//--------------------------------------------------------------------

#ifndef LISTARRAY_H
#define LISTARRAY_H

#include <stdexcept>
#include <iostream>

using namespace std;

template < typename DataType >
class List
{
  public:

    static const int MAX_LIST_SIZE = 10;   // Default maximum list size

    // Constructors
    List ( int maxNumber = MAX_LIST_SIZE );	// Default constructor
    List ( const List& source );		// Copy constructor
    
    // Overloaded assignment operator
    void operator= ( const List& source );

    // Destructor
    virtual ~List ();

    // List manipulation operations
    virtual void insert ( const DataType& newDataItem )  // Insert after cursor
	throw ( logic_error );  
    void remove () throw ( logic_error );        // Remove data item
    virtual void replace ( const DataType& newDataItem ) // Replace data item
	throw ( logic_error ); 
    void clear ();                               // Clear list

    // List status operations
    bool isEmpty () const;                    // List is empty
    bool isFull () const;                     // List is full

    // List iteration operations
    void gotoBeginning ()                     // Go to beginning
        throw ( logic_error );
    void gotoEnd ()                           // Go to end
        throw ( logic_error );
    bool gotoNext ()                          // Go to next data item
        throw ( logic_error );
    bool gotoPrior ()                         // Go to prior data item
        throw ( logic_error );
    DataType getCursor () const
        throw ( logic_error );                // Return data item

    // Output the list structure -- used in testing/debugging
    virtual void showStructure () const;

    // In-lab operations
    void moveToNth ( int n )                  // Move data item to pos. n
        throw ( logic_error );  
    bool find ( const DataType& searchDataItem )     // Find data item
        throw ( logic_error );  

  protected:

    // Data members
    int maxSize,
        size,             // Actual number of data item in the list
        cursor;           // Cursor array index
    DataType *dataItems;  // Array containing the list data item
};

#endif
Code:
#include "ListArray.h"

template < typename DataType >
List<DataType>::List(int maxNumber = MAX_LIST_SIZE)
{
	size = cursor = 0;
	maxSize = maxNumber;
	dataItems = new DataType [maxNumber];
	for(int i = 0; i < maxNumber; i++)
		dataItems[i] = NULL;
}

template < typename DataType >
List<DataType>::List(const List& source)
{
	maxSize = MAX_LIST_SIZE;
	
	dataItems = new DataType [MAX_LIST_SIZE];

	for(int i = 0; i < MAX_LIST_SIZE; i++)
		dataItems[i] = source.dataItems[i];

	size = source.size;
	cursor = source.cursor;
}

template < typename DataType >
void List<DataType>::operator= (const List<DataType> &source)
{
	this -> clear();
	for(int i = 0; i < maxSize; i++)
		dataItems[i] = source.dataItems[i];
	//return source;
}

template < typename DataType >
List<DataType>::~List()
{
	delete [] dataItems;
}

template < typename DataType >
void List<DataType>::insert(const DataType &newDataItem)
{
	if(size == 0)
		dataItems[cursor] = newDataItem;
	else
	{
		dataItems[cursor + 1] = newDataItem;
	}

	size++;
	cursor = size - 1;
}

template < typename DataType >
void List<DataType>::remove()
{
	dataItems[cursor] = NULL;
	size--;
	if(dataItems[cursor + 1] == NULL)
		cursor = 0;
	else
		cursor++;
}

template < typename DataType >
void List<DataType>::replace(const DataType &newDataItem)
{
	dataItems[cursor] = newDataItem;
}

template < typename DataType >
void List<DataType>::clear()
{
	for(int i = 0; i < size; i++)
		dataItems[i] = NULL;

	size = cursor = 0;
}

template < typename DataType >
bool List<DataType>::isEmpty() const
{
	return (size == 0);
}

template < typename DataType >
bool List<DataType>::isFull() const
{
	return (size == maxSize);
}

template < typename DataType >
void List<DataType>::gotoBeginning()
{
	cursor = 0;
}

template < typename DataType >
void List<DataType>::gotoEnd()
{
	cursor = size - 1;
}

template < typename DataType >
bool List<DataType>::gotoNext()
{
	if(dataItems[cursor + 1] != NULL)
	{
		cursor++;
		return true;
	}
	else
		return false;
}

template < typename DataType >
bool List<DataType>::gotoPrior()
{
	if(cursor != 0)
	{
		cursor--;
		return true;
	}
	else
		return false;
}

template < typename DataType >
DataType List<DataType>::getCursor() const
{
	return dataItems[cursor];
}

template < typename DataType >
void List<DataType>::showStructure() const
{
	cout << "Size: " << size << " Cursor: " << cursor << endl;
	cout << "List: ";
	for(int i = 0; i < maxSize; i++)
	{
		cout << dataItems[i];
		if(i != maxSize - 1)
			cout << ", ";
	}
	cout << endl;
}