1

I'm working on implementing a chain data structure, using a specific set of pre-made templates. Upon compilation, I'm receiving the error in the title.

arrayList.h:

#ifndef arrayList_h
#define arrayList_h

#include <iostream>
#include "linearList.h"


using namespace std;
template<class T>
class arrayList : public linearList<T>{
public:
    //constructor, copy constructor, destructor
    arrayList(int initialCapacity = 10);
    arrayList(const arrayList<T>&);
    ~arrayList() {delete [] element;};

    //ADT methods
    bool empty() const {return listSize == 0;};
    int size() const {return listSize;};
    T& get(int theIndex) const;
    int indexOf(const T& theElement) const;
    void erase(int theIndex);
    void insert(int theIndex, const T& theElement);
    void output(ostream& out) const;

    //additional method
    int capacity() const {return arrayLength;};

protected:
    void checkIndex(int theIndex) const;
    //throw illegalIndex if theIndex is invalid
    T* element;         //1D array to hold list elements
    int arrayLength;    //capacity of 1D array
    int listSize;       //number of elements in list
};
#endif

chain.h:

#ifndef chain_h
#define chain_h

#include <iostream>
#include "linearList.h"
#include "chainNode.h"

using namespace std;
template<class T>
class chain : public linearList<T>{
public:
    // constructor and destructor
    chain(int initialCapacity = 10);
    //chain(const chain<T>&);
    ~chain();

    // ADT methods
    bool empty() const {return listSize == 0;}
    int size() const {return listSize;}
    T& get(int theIndex) const;
    int indexOf(const T& theElement) const;
    void erase(int theIndex);
    void insert(int theIndex, const T& theElement);
    void output(ostream& out) const;


protected:
    void checkIndex(int theIndex) const;
    chain<T>* firstNode;
    int listSize;          
};
#endif

chainNode.h:

#ifndef chainNode_h
#define chainNode_h

#include <iostream>

template <class T>
struct chainNode
{
    // data members
    T element;
    chainNode<T> *next;

    // methods
    chainNode() {}
    chainNode(const T& element)
    {this->element = element;}
    chainNode(const T& element, chainNode<T>* next)
    {this->element = element;
        this->next = next;}
};


#endif

chain.cpp:

#include "chain.h"
#include "person.h"

using namespace std;

template<class T>
chain<T>::chain(int initialCapacity){
    // Constructor.
    /*if (initialCapacity < 1){
        ostringstream s;
        s << "Initial capacity = "
        << initialCapacity << " Must be > 0";
        throw illegalParameterValue(s.str());
    }*/
    firstNode = NULL;
    listSize = 0;
}

template<class T>
chain<T>::~chain(){
    // Chain destructor. Delete all nodes
    // in chain.
    while (firstNode != NULL){
        // delete firstNode
        chainNode<T>* nextNode = firstNode->next;
        delete firstNode;
        firstNode = nextNode;
    }
}

template<class T>
T& chain<T>::get(int theIndex) const{
    // Return element whose index is theIndex.
    checkIndex(theIndex);
    // move to desired node
    chainNode<T>* currentNode = firstNode;
    for (int i = 0; i < theIndex; i++)
        currentNode = currentNode->next;
    return currentNode->element;
}

template<class T>
int chain<T>::indexOf(const T& theElement) const{
    // search the chain for theElement
    chainNode<T>* currentNode = firstNode;
    int index = 0;  // index of currentNode
    while (currentNode != NULL && currentNode->element != theElement){
        // move to next node
        currentNode = currentNode->next;
        index++;
    }
    // make sure we found matching element
    if (currentNode == NULL)
        return -1;
    else
        return index;
}

template<class T>
void chain<T>::erase(int theIndex){
    checkIndex(theIndex);
    chainNode<T>* deleteNode;
    if (theIndex == 0){
        // remove first node from chain
        deleteNode = firstNode;
        firstNode = firstNode->next;
    }
    else{
        // use p to get to beforeNode
        chainNode<T>* p = firstNode;
        for (int i = 0; i < theIndex - 1; i++)
            p = p->next;
        deleteNode = p->next;
        p->next = p->next->next;
    }
    listSize--;
    delete deleteNode;
}

template<class T>
void chain<T>::insert(int theIndex, const T& theElement){
    if (theIndex < 0 || theIndex > listSize){
        // THROW ILLEGAL EXCEPTION
    }
    if (theIndex == 0) // insert at front
        firstNode = new chainNode<T>(theElement, firstNode);
    else{
        // find predecessor of new element
        chainNode<T>* p = firstNode;
        for (int i = 0; i < theIndex - 1; i++)
            p = p->next;
        // insert after p
        p->next = new chainNode<T>(theElement, p->next);
    }
    listSize++;
}

Person.h:

#ifndef Person_h
#define Person_h

#include <string>
#include <sstream>

using namespace std;

class Person{
public:
//Variables
    string birthdate;
    string first_name;
    string last_name;
    string hometownID;
    string hometownName;
    string userID;

    string name;
//Constructors
    Person();
    Person(string birthdate, string first_name, string last_name, string hometownID, string hometownName, string userID);
//Methods
    string getBirthdate();
    void setBirthdate(string birthdate);

    string getFirst_name();
    void setFirst_name(string first_name);

    string getLast_name();
    void setLast_name(string last_name);

    string getName();
    void setName(string name);

    string getHometownID();
    void setHometownID(string hometownID);

    string getHometownName();
    void setHometownName(string hometownName);

    string getUserID();
    void setUserID(string userID);


    int compare(Person& p, int criteria);



//Comparisons
    friend bool operator== (Person p1, Person p2);
    friend bool operator!= (Person &p1, Person &p2);

    friend bool operator> (Person &p1, Person &p2);
    friend bool operator>= (Person &p1, Person &p2);

    friend bool operator< (Person &p1, Person &p2);
    friend bool operator<= (Person &p1, Person &p2);

    friend ostream& operator<<(ostream& os, const Person& p);
};
#endif

Person.cpp: I've cut this down quite a bit. I currently don't have anything having to do with Node within this.

#include "Person.h"
#include <sstream>
#include <string>

using namespace std;

Person::Person(){
    birthdate = "";
    name = "";
    hometownID = "";
    hometownName = "";
    userID = "";
}
Person::Person(string birthdate, string first_name, string last_name, string hometownID, string hometownName, string userID){
    this->birthdate = birthdate;
    this->first_name = first_name;
    this->last_name = last_name;
    this->hometownID = hometownID;
    this->hometownName = hometownName;
    this->userID = userID;

    name = last_name+ ", " +first_name;
}

    //mostly get/set methods after here, nothing having to do with node.

main.cpp:

#include "arrayList.cpp"
#include "block_allocator.h"
#include "chain.cpp"
#include "chainNode.h"
#include "json.h"
#include "linearList.h"
#include "Person.h"

#include <string>
#include <fstream>
#include <streambuf>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <time.h>

using namespace std;

//ArrayList helper methods
arrayList<Person> arrayListStructure(string fileName);
int arrayListSort(int criteria, arrayList<Person>* list);
void arrayListReverseSort(int criteria, arrayList<Person>* list);
int arrayListFlip(arrayList<Person>* list);
//Chain helper methods
chain<Person> chainStructure(string fileName);
//Hashtable helper methods

int main(int argc, const char * argv[]){
    //get fileName
    cout << "Please enter a filename:" << endl;
    string fileName;
    cin >> fileName;

    //get data structure type
    cout << "Please choose a data structure:" << endl;
    cout << "     1. Arraylist" << endl;
    cout << "     2. Chain" << endl;
    cout << "     3. Hashtable" << endl;
    int dataStructure;
    cin >> dataStructure;

    cout << "Please choose a criteria:" << endl;
    cout << "     1. Name" << endl;
    cout << "     2. Birthday" << endl;
    cout << "     3. Location" << endl;
    int criteria;
    cin >> criteria;

    arrayList<Person> friends;
            chain<Person> friendChain;

    //parse file into data structure
    switch(dataStructure){
    case 1:     //Arraylist
        //edited out, irrelevant
    /*case 2:       
        //Chain
        //code goes here
        /*switch(criteria){
        case 1: //Name


        case 2: //Birthday
        case 3: //Location
        }
        break;*/
    /*case 3:
        //Hashtable
        //code goes here
        break;
    */
    }
}

//Helper methods for chain
chain<Person> chainStructure(string fileName){
    //create initial (empty) chain
    chain<Person> friends;

    //open input file
    ifstream fileInput(fileName);

    //turn input stream into string
    string inputStr((istreambuf_iterator<char>(fileInput)), istreambuf_iterator<char>());

    //parse file content into json object
    char *errorPos = 0;
    char *errorDesc = 0;
    int errorLine = 0;
    block_allocator allocator(1 << 10);

    json_value *root = json_parse(const_cast<char*>(inputStr.c_str()), &errorPos, &errorDesc, &errorLine, &allocator);

    //Take value of first element
    json_value *list = root->first_child;

    //Outer loop addresses each friend's JSON object
    for(json_value *it = list->first_child; it; it = it->next_sibling){
        string first_name, last_name, birthdate, hometownID, hometownName, userID;
        //Inner loop looks at each key/value pair within each friend object
        for(json_value *friendKeys = it->first_child; friendKeys; friendKeys = friendKeys->next_sibling){


            //grab first name
            if(!string(friendKeys->name).compare("first_name")){
                    first_name = friendKeys->string_value;
            }
            //grab last name
            else if(!string(friendKeys->name).compare("last_name")){
                last_name = friendKeys->string_value;
            }
            //grab birthday and trim to 5 characters
            else if(!string(friendKeys->name).compare("birthday")){
                birthdate = friendKeys->string_value;
                birthdate = birthdate.substr(0, 5);
            }
            //grab hometown info
            else if(!string(friendKeys->name).compare("hometown")){
                for(json_value *hometownKeys = friendKeys->first_child; hometownKeys; hometownKeys = hometownKeys->next_sibling){

                    if(!string(hometownKeys->name).compare("id")){
                        hometownID = hometownKeys->string_value;
                    }

                    if(!string(hometownKeys->name).compare("name")){
                        hometownName = hometownKeys->string_value;
                    }
                }
            }
            //grab userID
            else if(!string(friendKeys->name).compare("id")){
                userID = friendKeys->string_value;
            }


        }

        if(birthdate != "" && first_name != "" && last_name != "" && hometownID != "" && hometownName != "" && userID != ""){
            //Create new Person in chain
            Person person(birthdate, first_name, last_name, hometownID, hometownName, userID);
            friends.insert(friends.size(), person);
        }
    }
    //return friends;
    return friends;
}

//Helper methods for hashtable

So I know this is a huge wall of text, but I'm really not sure where this disconnect is, and I didn't want to provide too little information. Any help or advice would be greatly appreciated, as I'm very new to C++, and even more inexperienced with using the template system.

EDIT: linearList.h:

#ifndef linearList_h
#define linearList_h

#include <iostream>

using namespace std;

template<class T>
class linearList
{
public:
    virtual ~linearList() {};

    virtual bool empty() const = 0;
    // return true iff list is empty

    virtual int size() const = 0;
    // return number of elements in list

    virtual T& get(int theIndex) const = 0;
    // return element whose index is theIndex

    virtual int indexOf(const T& theElement) const = 0;
    // return index of first occurence of theElement

    virtual void erase(int theIndex) = 0;
    // remove the element whose index is theIndex

    virtual void insert(int theIndex, const T& theElement) = 0;
    // insert theElement so that its index is theIndex

    virtual void output(ostream& out) const = 0;
    // insert list into stream out
};

#endif
Taylor Bigham
  • 117
  • 1
  • 3
  • 10
  • where is the error coming from? – Eric Feb 15 '13 at 06:23
  • Sorry, the full error is: main.cpp 1>c:\users\taylor\dropbox\school\spring 2013\data structures\project2\project2\chain.cpp(25): error C2039: 'next' : is not a member of 'chain' 1> with 1> [ 1> T=Person 1> ] – Taylor Bigham Feb 15 '13 at 06:23
  • Anyone else just itching to see the definition of `linearList` ? Unless `linearList` provides it, `next` is only defined by `chainNode`, not `chain` (at least from the code you have here from what I see). – WhozCraig Feb 15 '13 at 06:25
  • I'll add that right away! – Taylor Bigham Feb 15 '13 at 06:26
  • @WhozCraig How could I rectify that situation, in that case? I'm really sorry, this doesn't make a ton of sense to me... – Taylor Bigham Feb 15 '13 at 06:28
  • Since we we don't have line numbers, and these are your source files, please, in the future, *mark* the line where the error is with a comment. On that note, is the error this line : `chainNode* nextNode = firstNode->next;` ? – WhozCraig Feb 15 '13 at 06:32
  • Just thinking about it, I'd guess that I needed to define a next pointer in my Person class, so that it can be called, but I'm not even sure how to go about that... – Taylor Bigham Feb 15 '13 at 06:33
  • Yes, that is the correct line. My apologies. – Taylor Bigham Feb 15 '13 at 06:34

1 Answers1

1

In chain.h, the chain<T> template has this for a member:

chain<T>* firstNode;

I'm pretty sure that should be:

chainNode<T>* firstNode;

There may be other errors (or maybe not), but that appears the likely one causing your current issue that is the subject of this question.

Side Bar: This thing needs a serious refactor to use the containers and algorithms from the standard library (std::vector<T>, std::list<T>, etc...) Just consider it.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • While this solved that particular error, as usual with these templates, it just allowed more errors to come to the forefront. I'm now receiving two more errors of this type: 1>main.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall chain::output(class std::basic_ostream > &)const " (?output@?$chain@VPerson@@@@UBEXAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@@Z) Any thoughts? – Taylor Bigham Feb 15 '13 at 06:53
  • @TaylorBigham: That's because you've put the template definitions in a source file. They need to go in a header, so that they're available wherever they are instantiated. See [this question](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) for details. – Mike Seymour Feb 15 '13 at 07:33
  • @TaylorBigham: And it's also because you haven't defined that function at all; you just declared it in the definition of `chain`. – Mike Seymour Feb 15 '13 at 07:35