undefined reference to (function) c++

83,419

Solution 1

How are you compiling your code? If you are using an IDE such as Microsoft Visual C++, be sure to create a project and add all of your .cpp files (not your .h files) to it. If you are using the command-line, be sure to include all of your filenames as command-line arguments. If this still doesn't help. Please include a description of the steps you are using to compile the program.

Edit:

There are several issues with your code:

  1. #ifndef ... #define... include guards are meant for files which will appear in #include directives in other files. Typically these are only .h files since it is strongly discouraged to #include .cpp files.

  2. Classes which use templates must all be in one .h file, not separated into a .h and .cpp file. (READ: In case I haven't made this clear enough, your LinkedSortedList class must ALL be in one .h file.)

  3. Your main.cpp file declares several functions which are not later defined. If you don't want to take the time to implement these functions yet, you need to at least add empty stubs for them.

  4. Be sure to compile and link all of your source files using a project in your IDE or using the correct command-line arguments. This is what I described in my original answer above.

Solution 2

To get templates instantiated automatically the compiler needs to the see the definition at the point of use. If you don't want to make the template definition visible you need to use explicit instantiation. How to do either of these is frequently answered.

BTW, please don't use names reserved for the implementation of the C++ compiler and its standard library as include guards: names starting with an underscore followed by a capital letter are reserved in all contexts for the C++ implementation.

Solution 3

My LinkedSortList.cpp is ...

That's the source of most of your problems. Doing what you did doesn't make sense. You need to define those inline in your header file, LinkedSortedList.h. That covers most of your problems the others, where are you defining empPrint(LinkedSortedList<Employee>&)?

Solution 4

First of all I cant see definition of these three:-

void empPrint (LinkedSortedList <Employee>& empList);
void empSave (LinkedSortedList <Employee>& empList, string file);
void empLoad (LinkedSortedList <Employee>& empList, string file);

Hope implementing them will reduce the errors.

Solution 5

C++ template methods and functions are not turned into machine code until the compiler runs into a call to the function with a specific type. But that means that the code that defines a template method, for example all of LinkedSortedList.cpp, actually does not produce any code at all when the compiler sees it.

You need to move all of the code from LinkedSortedList.cpp into LinkedSortedList.h (and similarly for the other templated classes) so that the compiler can produce the code for these methods when they are called. For example the compiler will generate the code for LinkedSortedList::LinkedSortedList() when it is called in main.cpp, but only if it's already seen the definition for this method in a header file.

Your other option is to use 'explicit instantiation' to force particular versions of particular methods to be compiled into object code.

Share:
83,419
JoshH
Author by

JoshH

Updated on July 09, 2022

Comments

  • JoshH
    JoshH almost 2 years

    Possible Duplicate:
    Undefined Reference to

    I've been banging my head against this one set of error messages for about 4 hours now and I can't seem to figure it out. I've not posted here before, so I apologize in advance if it's not in the right area or I've done something wrong. At any rate, the error messages I'm receiving are:

    main.cpp|28|undefined reference to `LinkedSortedList<Employee>::LinkedSortedList()'|
       main.cpp|52|undefined reference to `empPrint(LinkedSortedList<Employee>&)'|
       main.cpp|58|undefined reference to `empSave(LinkedSortedList<Employee>&, std::string)'|
       main.cpp|65|undefined reference to `empLoad(LinkedSortedList<Employee>&, std::string)'|
       main.cpp|70|undefined reference to `LinkedSortedList<Employee>::~LinkedSortedList()'|
       main.cpp|70|undefined reference to `LinkedSortedList<Employee>::~LinkedSortedList()'|
    
       obj\Debug\main.o||In function `Z9empSearchR16LinkedSortedListI8EmployeeE':|
       main.cpp|109|undefined reference to `LinkedSortedList<Employee>::getHead()'|
    

    My main.cpp is as follows:

    #include <iostream>
    #include <string>
    #include <stdio.h>
    #include <fstream>
    #include "SortedList.h"
    #include "LinkedSortedList.h"
    #include "Employee.h"
    #include "LinkedNode.h"
    
    using namespace std;
    
    void newEmp(LinkedSortedList <Employee>& empList);
    void empSearch(LinkedSortedList <Employee>& empList);
    void empPrint(LinkedSortedList <Employee>& empList);
    void empSave(LinkedSortedList <Employee>& empList, string file);
    void empLoad(LinkedSortedList <Employee>& empList, string file);
    
    int main()
    {
        //int empID;
        bool menuFinish = false;
        LinkedSortedList<Employee> empList;
        char selection;
    
        while (!menuFinish)
    
            //simple menu system through cout, the selection is read in through cin
            //and converted to upper case for simplicity during the conditionals
            cout << "Menu" << endl;
            cout << "(I)nsert new record" << endl;
            cout << "(E)mployee ID search" << endl;
            cout << "(P)rint employee info" << endl;
            cout << "(S)ave database to a file" << endl;
            cout << "(L)oad database from file" << endl;
            cout << "(Q)uit" << endl;
            cout << "Enter selection " << endl;
            cin >> selection;
            selection = toupper(selection);
    
            //menu selections are compared with their functions
            if (selection == 'I')
                newEmp(empList);
            else if (selection == 'E')
                empSearch(empList);
            else if (selection == 'P')
                empPrint(empList);
            else if (selection == 'S')
                {
                    string fileName;
                    cout << "Enter a filename to save the database to " << endl;
                    cin >> fileName;
                    empSave(empList, fileName);
                }
            else if (selection == 'L')
                {
                    string fileName;
                    cout << "Enter the filename to load the database from " << endl;
                    cin >> fileName;
                    empLoad(empList, fileName);
                }
            else if (selection == 'Q')
                menuFinish = true;
            else
                cout << "Incorrect choice " << endl;
    }
    
    //function creates a new employee
    void newEmp(LinkedSortedList <Employee>& empList)
    {
        string firstName;
        string lastName;
        int empID = -1;
    
        cout << "Please enter the first name " << endl;
        cin >> firstName;
        cout << "Please enter the last name " << endl;
        cin >> lastName;
        while (empID > 9999999 || empID < 0)
            {
            cout <<"Please enter the employee ID " << endl;
            cin >> empID;
    
            }
        //puts the employee in the db unless they're already found, then outputs an
        //error on the screen
        Employee emp(firstName, lastName, empID);
        bool findEmp = empList.find(emp);
    
        if (!findEmp)
            empList.insert(emp);
        else
            cout << "Emlpoyee ID " << empID << " already in use " << endl;
    }
    
    //function to search for an employee based on their employee ID
    void empSearch (LinkedSortedList <Employee>& empList)
    {
        int empID;
        int sizeOfList = 0;
        bool noEmp = true;
    
        cout << "Enter employee ID " << endl;
        cin >> empID;
    
        LinkedNode <Employee>* temp = empList.getHead();
        while (sizeOfList < empList.size() && noEmp)
        {
            sizeOfList++;
            if (empID == temp->value.getEmpID())
                {
                    cout << "Searched " << sizeOfList << "employees " << endl;
                    cout << "Found record: " << temp->value;
                    noEmp = false;
                }
                temp = temp->next;
        }
        if (noEmp)
        cout << "Search of " << sizeOfList << " employees.  Employee not found" << endl;
    
    }
    
    //function used to print the first and last five employees from the db
    void empPrint (LinkedSortedList <Employee>& empList)
    {
        if (empList.size() <= 10)
            {
                empList.print();
            }
    
            else
            {
                LinkedNode<Employee>* temp = empList.getHead();
                cout << "First five employees: " << endl;
    
                for (int i = 0; i < 5; i++)
                    {
                    cout << temp->value << endl;
                    i++;
                    temp = temp->next;
                    }
    
                int midList = empList.size()-5;
                for (int i = 0; i < midList; i++)
                    {
                         temp = temp->next;
                    }
    
                cout << "Last five employees: " << endl;
                for (int i = 0; i < 5; i++)
                    {
                        cout << temp->value << endl;
                        i++;
                        temp = temp->next;
                    }
            }
    }
    
    //function used to save the employee information from the db to a file
    void empSave(LinkedSortedList<Employee>& empList, string fileName)
    {
        string lastName;
        string firstName;
        //int empID;
        ofstream output;
        output.open(fileName.c_str());
        if (!output)
            {
                cout << "File not saved" << endl;
            }
        else
        {
            LinkedNode<Employee>* temp = empList.getHead();
            int i = 0;
            while (i < empList.size())
            {
                output << temp->value.getLastName() << " " << temp->value.getFirstName() << " " << temp->value.getEmpID() << endl;
                i++;
                temp = temp->next;
            }
        }
        output.close();
    }
    
    //function used to load the employee information from a file to the db
    void empLoad(LinkedSortedList<Employee>& empList, string fileName)
    {
        if (empList.size() > 0)
        {
            empList.clear();
        }
    
        ifstream input;
        input.open(fileName.c_str());
    
        if (!input)
        {
            cout << "No file exists" << endl;
        }
    
        else
        {
            int empID;
            string firstName;
            string lastName;
            string delimiter;
    
            while(input.good());
            {
                getline(input, delimiter, '\n');
                getline(input, lastName, ' ');
                getline(input, firstName, ' ');
                input >> empID;
    
                Employee emp(lastName, firstName, empID);
    
                bool empFound = empList.find(emp);
    
                if(!empFound)
                {
                    empList.insert(emp);
                }
                else
                cout << "Employee already exists" << endl;
            }
        }
    }
    

    My LinkedSortList.cpp is:

    #ifndef _LinkedSortedList_
    #define _LinkedSortedList_
    
    #include "Employee.h"
    #include "LinkedSortedList.h"
    #include "SortedList.h"
    #include "LinkedNode.h"
    
    #include <iostream>
    #include <fstream>
    #include <string>
    
    
    using namespace std;
    
    //default constructor
    //sets head to null and makes the size of the list 0
    template <class Elem>
    LinkedSortedList<Elem>::LinkedSortedList()
    {
        head = NULL;
        listSize = 0;
    }
    
    //destructor, clears list THEN deletes the head so memory leaks are
    //stopped
    template <class Elem>
    LinkedSortedList<Elem>::~LinkedSortedList()
    {
        clear();
        delete head;
    }
    
    //clears the list, freeing memory and stopping leaks and resets the
    //list size
    template <class Elem>
    void LinkedSortedList<Elem>::clear()
    {
        LinkedNode<Elem> *indexPtr = head;
    
        while (head != NULL)
        {
            head = head->next;
            delete indexPtr;
            indexPtr = head;
        }
        listSize = 0;
    }
    
    //finds a search value in the list... if it finds it then it returns true,
    //otherwise it returns false
    template <class Elem>
    bool LinkedSortedList<Elem>::find(Elem searchValue) const
    {
        LinkedNode<Elem>* indexPtr = head;
        while (indexPtr != NULL)
        {
            if (indexPtr->value == searchValue)
            {
                return true;
            }
            indexPtr = indexPtr->next;
    
    
        }
        return false;
    }
    
    //gets and DELETES first value in the list - if it finds nothing then
    //return false, otherwise true
    template <class Elem>
    bool LinkedSortedList<Elem>::getFirst(Elem &returnValue)
    {
        LinkedNode<Elem>* indexPtr = head;
        if (indexPtr == NULL)
            return false;
            else
            {
                head = head->next;
                returnValue = indexPtr->value;
                delete indexPtr;
                listSize--;
                return true;
            }
            returnValue = indexPtr->value;
    }
    
    //prints the list to cout or prints a warning if the list contains
    //no values
    template <class Elem>
    void LinkedSortedList<Elem>::print() const
    {
    
        if (head == NULL)
        {
             cout << "No elements in the list" << endl;
        }
            else
            {
                LinkedNode<Elem>* indexPtr = head;
                while (indexPtr != NULL)
                {
                    cout << indexPtr->value << endl;
                    indexPtr = indexPtr->next;
                }
            }
    }
    
    //returns the size of the list to the caller
    template <class Elem>
    int LinkedSortedList<Elem>::size() const
    {
        return listSize;
    }
    
    //inserts a value into the list where it should go, if the list is empty it will
    //say there are no existing nodes
    template <class Elem>
    bool LinkedSortedList<Elem>::insert(Elem newValue)
    {
        LinkedNode<Elem>* indexPtr = head;
        LinkedNode<Elem>* newNode;
        //newNode->value = newValue;
    
         try
        {
            newNode = new LinkedNode<Elem>(newValue);
        }
        catch(exception e)
        {
            cout<<"Exception reached: " << e.what() << endl;
            return false;
        }
    
        //checks to see if the list is empty, if it is then it makes the newNode
        //the head
        if (head == NULL)
            {
                cout << "No existing nodes" << endl;
                head = newNode;
                cout << "First node is now " << head->value << endl;
                listSize++;
                return true;
            }
    
            /*looks to see if the value of the newNode is less than or equal to the
            index, if it is then it sets the point of the newNode equal to the head
            then makes the head the newNode and increments the listSize by one to keep
            track of the size of the list and returns true*/
            else if (newNode->value <= head->value)
            {
                newNode->next = head;
                head = newNode;
                listSize++;
                return true;
            }
    
            /*if the newNode value is greater than the index, then:*/
            else
            {
                while(indexPtr->next != NULL && newNode->value > indexPtr->next->value)
                    {
                        indexPtr = indexPtr->next;
                    }
    
                if (indexPtr->next == NULL)
                {
                    indexPtr->next = newNode;
                    listSize++;
                    return true;
                }
                else
                {
                    newNode->next = indexPtr->next;
                    indexPtr->next = newNode;
                    listSize++;
                    return true;
                }
    
            }
    }
    //added for project 2 to return the head of the LL
    template <class Elem>
    LinkedNode<Elem>* LinkedSortedList<Elem>::getHead()
    {
        return head;
    }
    
    
    #endif
    

    The Employee.cpp is:

    #ifndef _Employee_
    #define _Employee_
    
    #include "Employee.h"
    #include "LinkedSortedList.h"
    #include <iostream>
    #include <fstream>
    #include <string>
    
    using namespace std;
    
    //blank default constructor
    Employee::Employee()
    {
    }
    
    //constructor that takes 3 parameters and sets them
    Employee::Employee(string lastName, string firstName, int eID)
    {
        this->lastName = lastName;
        this->firstName = firstName;
        this->empID = eID;
    }
    
    //blank deconstructor
    Employee::~Employee()
    {
    }
    
    //overloaded equality operator
    bool Employee::operator==(Employee &nextEmployee)
    {
        if (this->empID == nextEmployee.empID)
                return true;
            else
                return false;
    }
    
    //overloaded less than or equal to operator
    bool Employee::operator <= (Employee &nextEmployee)
    {
        if (this->empID <= nextEmployee.empID)
                return true;
            else
                return false;
    }
    
    //overloaded greater than or equal to operator
    bool Employee::operator >= (Employee &nextEmployee)
    {
        if (this->empID >= nextEmployee.empID)
                return true;
            else
                return false;
    }
    
    //overloaded less than operator
    bool Employee::operator < (Employee &nextEmployee)
    {
        if (this->empID < nextEmployee.empID)
                return true;
            else
                return false;
    }
    
    //overloaded greater than operator
    bool Employee::operator > (Employee &nextEmployee)
    {
        if (this->empID > nextEmployee.empID)
                return true;
            else
                return false;
    }
    
    // overloaded output stream operator
    ostream& operator<<(ostream& os, const Employee empl)
    {
        os << "Last: " << empl.lastName << endl;
        os << "First: " << empl.firstName << endl;
        os << "Employee ID: " << empl.empID << endl;
        return os;
    }
    
    #endif
    

    My header file, LinkedSortedList.h:

    #ifndef _LinkedSortedListClass_
    #define _LinkedSortedListClass_
    
    #include "SortedList.h"
    #include "LinkedNode.h"
    
    #include <iostream>
    #include <fstream>
    #include <string>
    
    //using namespace std;
    
    template <class Elem>
    class LinkedSortedList : public SortedList< Elem >
    {
    public:
        LinkedSortedList();
        ~LinkedSortedList();
        virtual void clear();
        virtual bool insert(Elem newValue);
        virtual bool getFirst(Elem &returnValue);
        virtual void print() const;
        virtual bool find(Elem searchValue) const;
        virtual int size() const;
        LinkedNode<Elem>* getHead(); //added for project 2
    
    private:
        LinkedNode<Elem>* head;
        int listSize;
    };
    #endif
    

    And finally (WHEW!) my Employee.h is here:

    #ifndef _EmployeeClass_
    #define _EmployeeClass_
    
    #include <iostream>
    #include <fstream>
    #include <string>
    
    using namespace std;
    
    class Employee
    {
        public:
            Employee();
            ~Employee();
            Employee(string, string, int);
            bool operator == (Employee& nextEmployee);
            bool operator <= (Employee &nextEmployee);
            bool operator >= (Employee &nextEmployee);
            bool operator < (Employee &nextEmployee);
            bool operator > (Employee &nextEmployee);
            friend ostream& operator<<(ostream& os, const Employee empl);
            string getLastName(){return lastName;}
            string getFirstName(){return firstName;}
            int getEmpID(){return empID;}
        private:
            string lastName;
            string firstName;
            int empID;
    };
    
    #endif
    

    I'm just not seeing the problem here, I've spoken to my TA, the helproom staff and other students. I haven't heard back from the prof yet, but I doubt I'll hear from her this weekend anyway. Thank you VERY much for any insight you can provide. I need some tylenol. -Josh

    • chris
      chris over 11 years
      Change your header guard names. They're reserved.
    • Code-Apprentice
      Code-Apprentice over 11 years
      @chris While a good suggestion, I don't think that will solve the linker errors.
    • Pete Becker
      Pete Becker over 11 years
      Neither of these has anything to do with the problem you're seeing, but they're still important. First, the names of the include guards in the header files are reserved to the implementation. Don't use names that contain two underscores or begin with an underscore followed by a capital letter. Second, don't use include guards in source files.
  • Griwes
    Griwes over 11 years
    This is true in general case, but first thing you think about when somebody asks about undefined reference in C++ should be "does he use templates and separate declaration from definition?".
  • Code-Apprentice
    Code-Apprentice over 11 years
    @Griwes Good point...although not the first thing I think about ;-)
  • JoshH
    JoshH over 11 years
    Those are defined inside the main.cpp, I apparently didn't copy the rest of the code into the question.
  • JoshH
    JoshH over 11 years
    I'm using an IDE called CodeBlocks, for my first proejct (the LinkedSortedList) it seemed to do well. In CodeBlocks I simple have all of the .cpp and .h files included in one project (project2) and click "Build and Run". My main didn't copy into the text fied on this site correctly, so the bottom implementations of those functions are missing.
  • JoshH
    JoshH over 11 years
    That is being defined in my main.cpp. Are you suggesting that I move my LinkedSortedList functions from their .cpp file to the .h file?
  • Code-Apprentice
    Code-Apprentice over 11 years
    @user1727170 Ignore points 3. and 4. then. Points 1. and 2. are the important ones to fix your problems.
  • JoshH
    JoshH over 11 years
    I have updated my code so the main.cpp is properly shown now, at least it should be. I'm honestly a bit lost with the header guards, each comment here has mentioned that they're a big no-no, I've tried removing them and that exacerbates my error messages.
  • Code-Apprentice
    Code-Apprentice over 11 years
    @user1727170 I think you miss the point. Header guards are a great tool when used correctly. They are not meant to be used in .cpp files, only in .h files. However, that isn't the cause of most of your errors. The main point is you need to fix your template class as I stated in point 2 in my answer.
  • Code-Apprentice
    Code-Apprentice over 11 years
    @user1727170 If you are still getting errors after making that change, please edit your question and let us know what they are.
  • JoshH
    JoshH over 11 years
    I figured out the explicit template instantiaion, I simply added: template class LinkedSortedList <Employee>; to the bottom of my LinkedSortList.cpp and it compiled correctly. Thank you for your help!
  • Code-Apprentice
    Code-Apprentice over 11 years
    @user1727170 That might solve your immediate problem, but what if you want LinkedSortedList<int> and LinkedSortedList<double>, too? And what if I take your .obj files and want to create LinkedSortedList<MyVerySpecialClass>? Please read point #2 again.
  • Code-Apprentice
    Code-Apprentice over 11 years
    @user1727170 Okay, maybe I missed a little detail. I edited my answer to hopefully be more clear.
  • Instinct
    Instinct about 10 years
    @Code-Guru this answer was a huge help for a problem i've run into using template linkedlists and template nodes! Why is it that template classes can't have declaration/implementation separated? (was getting undefined errors trying to instantiate a new template linkedlist in main, works now)
  • Code-Apprentice
    Code-Apprentice about 10 years
    @Instinct It is because a template doesn't actually define a function or class. It simply gives a recipe for a family of functions or classes. The compiler needs the full template definition in order to instantiate specific versions of the function or class from that recipe.