Undefined Reference Error

Hello,

When I compile this code I get an error message stating "undefined reference to Doctor::compare(Doctor)" - even though I've declared the compare function in the header file and implemented it in the Doctor.cpp file. Where the error is occuring in the program below has been noted with a /***** ... ******/ comment.

Why am I getting this error?

Note: I've also tried writing that line as:
int compareResut = doc1.compare(Doctor::doc2);

But when writing this, I then get the error message " 'doc2' is not a member
of 'Doctor':.

How can I get the result of the compare function?

Thank you!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

// main program

#include <iostream>
#include <ostream>
#include <Doctor.h>
#include <vector>
#include <map>

using namespace std;

int main()
{
    string name = "Bob";

    // Instantiating two Doctor objects with two different constructors.
    Doctor doc1 (name);
    Doctor doc2;

    doc2.setName("Alice");
    doc2.setID(2020);

    // Checking that the setter methods worked.
    cout << "\ndoc1 name: " + doc1.getName() << endl;
    cout << "doc2 name: " + doc2.getName() << endl;

    // Calling a getter method in a print statement that returns an int.
    cout << "doc1 id: " << doc1.getID() << endl;
    cout << "doc2 id: " << doc2.getID() << endl;

    // This code instantiates a vector object
    std::vector<Doctor> docList;

    // This code adds the elements to the back of the vector list.
    docList.push_back(doc2);
    docList.push_back(doc1);

  /******* Error occuring on the line below ********/
    int compareResult = doc1.compare(doc2);

    cout << "result: " << compareResult << endl;


    return 0;
} // end of main

// beginning of Doctor header file

#ifndef DOCTOR_H
#define DOCTOR_H

#include <string>

class Doctor
{

    private:
        std::string name;
        int id;

    public:
        Doctor();
        Doctor (std::string n);
        Doctor (std::string n, int num);
        //virtual ~Doctor();

        std::string getName(){return name;}
        void setName(std::string);

        int getID(){return id;}
        void setID(int num);

        int compare(Doctor doc2);

};

#endif // DOCTOR_H

// End of Doctor header file

// Beginning of Doctor.cpp file

#include "Doctor.h"

using namespace std;

string name;
int id;

Doctor::Doctor()
{
    name = "BLANK NAME";
    id = 99999;
}

Doctor::Doctor(string n)
{
    name = n;
}

Doctor::Doctor(string n, int fig)
{
    name = n;
    id = fig;
}

/*Doctor::~Doctor()
{
    //dtor
}*/

string getName(){ return name;}

void Doctor::setName(string n){ name = n;}

int getID() {return id;}

void Doctor::setID(int fig){ id = fig;}

int compare(Doctor doc2){
    if (id > doc2.getID()){

        return 1;
    } else {
        if (id < doc2.getID()){

            return -1;
        } else {

            return 0;
        }
    }
}    // End of Doctor.cpp file


1
2
3
4
5
6
7
8
9
string getName(){ return name;}

void Doctor::setName(string n){ name = n;}

int getID() {return id;}

void Doctor::setID(int fig){ id = fig;}

int compare(Doctor doc2){
¿what does Doctor:: mean? you write it before setName and setID, but not on getName, getID and compare
Hello ne555,

For some reason, my compiler wasn't allowing those void functions to work. But when I added the Doctor:: it some how allowed the void functions to work.

Perhaps the error is somewhere here? I'm a bit new to C++ here so I was thinking, because of it not working without the Doctor::, that including Doctor:: was the C++ syntax for void functions. But I must be wrong here, yeah?
What ne555 said + bewere you are going to redefine two methods:
Inside Doctor.h:
1
2
std::string getName(){return name;}
int getID(){return id;}


Inside Doctor.cpp:
1
2
string getName(){ return name;}
int getID() {return id;}



- - -
You are also shadowing your properties with two global variables:
Inside Doctor.h:
1
2
3
private:
    std::string name;
    int id;


Inside Doctor.cpp:
1
2
string name;
int id;



- - -
Also:
1
2
3
4
Doctor::Doctor(string n)
{
    name = n;
}

I don’t like this: Doctor::id is left uninitialized by this constructor.


- - -
Inside main():
 
#include <Doctor.h> 

should probably become:
 
#include "Doctor.h" 


- - -
Inside compare():
1
2
3
4
5
6
7
8
if (id > doc2.getID()){

    return 1;
} else {                        // unify these
    if (id < doc2.getID()){     // two rows

        return -1;
    } else {

Since the if is the only instruction inside the else, you can write it this way:
1
2
3
4
5
if (id > doc2.getID()){
    return 1;
} else if (id < doc2.getID()) {
        return -1;
} else {


C++ doesn't add compare's definition to your declaration, because you didn't add a class name to tell it which header file contains the compare method. That's what "Doctor::" does. It tells the compiler that your compare method's definition defines the method declared in Doctor.

Let's go over your methods for the Doctor class. We'll start with your header file.

The following methods are declared, but not yet defined. The compiler expects to find definitions for all of these in the c++ file with definitions that are exactly the same, except they add Doctor:: before the method name and add a body {} which contains the definition. The compiler needs Doctor:: before the method name to know which class the method belongs to. If there is no class named, the method is a static method that doesn't belong to any class. I will revisit this last part later.
1
2
3
4
5
 Doctor();
        Doctor (std::string n);
        Doctor (std::string n, int num);
        //virtual ~Doctor();
        int compare(Doctor doc2);


The following methods are defined. Because they are defined inside a class, the compiler knows these methods are part of the Doctor class. Notice how you were able to declare and define the methods at the same time.
1
2
3
4
        std::string getName(){return name;}
        void setName(std::string);
        int getID(){return id;}
        void setID(int num);


Now for the methods in your c++ file.

Notice how the methods are all outside of a class. This means the unless you specify which class the methods belong to, they will be considered static methods that don't belong to any class. Notice also that the methods have a body {}. This means all methods following are defined. Your constructors tell the compiler that the Doctor() methods belong to the Doctor class because you added Doctor:: before the name. This tells the compiler to look for a declaration in the Doctor class and to add the definition to it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Doctor::Doctor()
{
    name = "BLANK NAME";
    id = 99999;
}

Doctor::Doctor(string n)
{
    name = n;
}

Doctor::Doctor(string n, int fig)
{
    name = n;
    id = fig;
}

/*Doctor::~Doctor()
{
    //dtor
}*/

void Doctor::setName(string n){ name = n;}

void Doctor::setID(int fig){ id = fig;}


Now consider what follows. The compiler will see these definitions and see that there is no declaration, because your declarations are in a Class and the method names don't specify a class. This means the compiler sees these as declarations and definitions.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string getName(){ return name;}

int getID() {return id;}

int compare(Doctor doc2){
    if (id > doc2.getID()){

        return 1;
    } else {
        if (id < doc2.getID()){

            return -1;
        } else {

            return 0;
        }
    }


This leads me to the final piece. The name and id in your c++ file are static variables. They also do not belong to a class because they are outside of a class. This means that the methods in the last section are using these variables instead of the variables that the Doctor contains. If you delete these, you will get an error for every method that uses those variables and this is a good thing! Now you will see that your static methods were acting on static variables and you can fix the error by adding the class name before the methods.
1
2
string name;
int id;


I suggest you look at
http://www.cplusplus.com/doc/tutorial/classes/
if you have trouble understanding anything I wrote.
And in one complete picture - only fairly minor changes required:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// beginning of Doctor header file
#ifndef DOCTOR_H
#define DOCTOR_H

#include <string>

class Doctor
{
private:
    std::string name;
    int id;
    
public:
    Doctor();
    Doctor (std::string );
    Doctor (std::string , int);
    ~Doctor(){}; // <--
    
    std::string getName(); // <-- SHOULD ONLY SHOW HEADERS, NOT DEFINITIONS
    void setName(std::string);
    
    int getID(); // <--
    void setID(int);
    
    int compare(Doctor);
};
#endif // DOCTOR_H

//#include "Doctor.h"
Doctor::Doctor()
{
    name = "BLANK NAME";
    id = 99999;
}

Doctor::Doctor(std::string n)
{
    name = n;
}

Doctor::Doctor(std::string n, int fig)
{
    name = n;
    id = fig;
}

void Doctor::setName(std::string n){ name = n;}
void Doctor::setID(int fig){ id = fig;}
std::string Doctor::getName(){return name;} // <-- Doctor::
int Doctor::getID(){return id;} // <--
int Doctor::compare(Doctor doc2) // <--
{
    if (id > doc2.getID()) // <-- ANOTHER WAY OF DOING THE SAME
        return 1;
    
    if (id < doc2.getID())
        return -1;
    
    return 0;
}
// End of Doctor.cpp file

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    std::string name = "Bob";
    
    // Instantiating two Doctor objects with two different constructors.
    Doctor doc1 (name);
    Doctor doc2;
    
    doc2.setName("Alice");
    doc2.setID(2020);
    
    // Checking that the setter methods worked.
    cout << "\ndoc1 name: " + doc1.getName() << endl;
    cout << "doc2 name: " + doc2.getName() << endl;
    
    // Calling a getter method in a print statement that returns an int.
    cout << "doc1 id: " << doc1.getID() << endl;
    cout << "doc2 id: " << doc2.getID() << endl;
    
    // This code instantiates a vector object
    std::vector<Doctor> docList;
    
    // This code adds the elements to the back of the vector list.
    docList.push_back(doc2);
    docList.push_back(doc1);
    
    /******* Error occuring on the line below ********/
    int compareResult = doc1.compare(doc2);
    cout << "result: " << compareResult << endl;
    
    return 0;
} // end of main 


doc1 name: Bob
doc2 name: Alice
doc1 id: 0
doc2 id: 2020
result: -1
Program ended with exit code: 0
Thank you to all for the assistance.
Topic archived. No new replies allowed.