Undefined Reference Errors

I've been working on a C++ project the last couple days and this has really stopped me in my tracks. When I attempt to run the program I get multiple instances of the "undefined reference to 'Class::Function'". I've checked over my code a dozen times and scoured past forum posts for hours and I'm just lost.

I have the functions defined in the implementation file and their prototypes declared in the specification (header) file. I'm pretty sure I have the correct #include statements set up, but from what I've read this seems to be an issue where I didn't properly link the files together.

Specification (Header) File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <string>

using namespace std;

class Song {

public:
    Song();
    Song(string newTitle, string newArtist, string newAlbum);
    string GetSongTitle() const;
    string GetArtistName() const;
    string GetAlbumName() const;
    void SetSongTitle(string newTitle);
    void SetArtistName(string newArtist);
    void SetAlbumName(string newAlbum);
    string DisplaySongData() const;

private:
    string name;
    string artist;
    string album;

};



Implementation File
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
/*  Implementation file (song.cpp)
   To be used in conjunction with song.h
*/

#include <iostream>
#include <string>
#include "Song.h"

using namespace std;

Song::Song() {
    name = " ";
    artist = " ";
    album = " ";
}

Song::Song(string newTitle, string newArtist, string newAlbum) {
    name = newTitle;
    artist = newArtist;
    album = newAlbum;
}

string Song::GetSongTitle() const {
    return name;
}

string Song::GetArtistName() const {
    return artist;
}

string Song::GetAlbumName() const {
    return album;
}

void Song::SetSongTitle(string newTitle) {
    name = newTitle;
}

void Song::SetArtistName(string newArtist) {
    artist = newArtist;
}

void Song::SetAlbumName(string newAlbum) {
    album = newAlbum;
}

string Song::DisplaySongData() const {
    string displayString;
    displayString = "Title: " + name + "\n" + "Artist: " + artist + "\n" + "Album: " + album;
    return "Title: " + name + "\n" + "Artist: " + artist + "\n" + "Album: " + album;
}


Driver File

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
#include "Song.h"
#include <fstream>
#include <iostream>
#include <string>

using namespace std;

// Function Prototypes Declared
void whiteSpaceRemover(Song songList[], int lineCount);         // Called to trim the whitespace from a string
string equalityTestPrep(string str);                            // Removes spaces and converts to lowercase to facilitate string comparisons

// Main function
int main() {

    // Variable declarations
    string artistSearch, songTitle, artistName, albumName;
    int lineCount = 0, count = 0;
    int token = 0, token2 = 0, token3 = 0;

    // Opens input stream for the file
    ifstream songFile;
    songFile.open("song.in");

    // Cycles through the file to evaluate how large an array is needed
    while (getline(songFile, artistSearch)) {
        lineCount++;
    }

    artistSearch = "";

    // Closes file to be re-opened to reset the line reader
    songFile.close();

    songFile.open("song.in");

    Song songList[lineCount];
    string songs[lineCount];

    // Stores each line of the file into an array of strings
    while (songFile) {
        getline(songFile, songs[count]);
        count++;
    }

    // Breaks up and assigns the string values from songs[] to the songList type
    for (int i = 0; i < lineCount; i++) {
        token = songs[i].find(':');
        if(token != string::npos)
            songList[i].SetSongTitle(songs[i].substr(0, token));
        token2 = songs[i].substr(token + 1, songs[i].length() - 1).find(':') + token;
        if(token2 != string::npos)
            songList[i].SetArtistName(songs[i].substr(token + 1, token2 - token));
        token3 = songs[i].length() - 1;
        if(token3 != string::npos)
            songList[i].SetAlbumName(songs[i].substr(token2 + 1, token3 - token2));
    }

    songFile.close();

    // Prompts the user for the artist by which to search the library for
    cout << "Enter the artist to search for: ";
    getline(cin, artistSearch);
    cout << endl << endl;

    // Calls the function to remove excess whitespace from the strings within the songList array
    whiteSpaceRemover(songList, lineCount);

    // Tests for equality and outputs all information related to the artist
    for(int i = 0; i < lineCount; i++) {
        songTitle = songList[i].GetArtistName();
        if(equalityTestPrep(songTitle) == equalityTestPrep(artistSearch)) {
            artistName = songList[i].GetArtistName();
            albumName = songList[i].GetAlbumName();
            cout << songTitle << " : " << artistName << " : " << albumName << endl;
        }
    }


}

// Trims the whitespace from the songList[] strings for prettier output and better organization
void whiteSpaceRemover(Song songList[], int lineCount) {

    int token;
    string songTitle, artistName, albumName;

    for(int i = 0; i < lineCount; i++) {
        songTitle = songList[i].GetSongTitle();
        token = songTitle.find('\t');
        if(token != string::npos)
            songList[i].SetSongTitle(songTitle.substr(0, token));
        artistName = songList[i].GetArtistName();
        token = artistName.find_first_not_of('\t');
        if(token != string::npos) {
            songList[i].SetArtistName(artistName.substr(token, artistName.find('\t') - token));
            songList[i].SetArtistName(artistName.substr(0, artistName.find('\t')));
        }
        albumName = songList[i].GetAlbumName();
        token = albumName.find('\t');
        if(token != string::npos)
            songList[i].SetAlbumName(albumName.substr(1, token));
    }

}


I'm sure there are little errors throughout the program, as well as parts that don't seem to do much. I haven't completed the program, but am concerned about continuing before I resolve this current issue. I probably made some silly mistake, but I'm just not seeing it.

Thanks for your time.
You have not implemented equalityTestPrep.
I have it implemented in my current program, I had clipped it out since it seemed irrelevant. I'm still fairly sure it has nothing to do with my error, but I'll post it here regardless. Sorry for the confusion.

1
2
3
4
5
6
7
8
9
// Sets the two strings to be compared to lower case
string equalityTestPrep (string str) {

    // Sets all to lowercase
	for(int i = 0; i < str.length(); i++)
		str[i] = tolower(str[i]);

    return str;
}
Last edited on
where I didn't properly link the files together.

At risk of telling you what you already know, the solution is to properly link the files together.


Last edited on
It is probably as you said that you don't link the files correctly.
Therein lies the issue. I'm not sure how to go about linking them properly. Is there more to linking them than the hierarchy involved in the #include statements? Is there something outside of the code I need to mess with?

I've just recently started using classes in C++ and my book is either too vague or I'm too dense to understand what I need to do here.
Is there more to linking them than the hierarchy involved in the #include statements?


Yes. That's got nothing at all to do with linking. Not a thing. A #include statement instructs the preprocessor to copy the named file exactly, and paste it into that position. That's all it does.

Every cpp file gets compiled into a single object file. In this case, your two cpp files will generate two object files. The linker needs to know about both of them, and needs to know that they are both to be used in making the final executable.

If I were building your code, I would use the following command line:

g++ song.cpp main.cpp

and it would work (I've guessed names for your cpp files, hopefully it's clear).

How are you compiling your code?

Edit: As an aside, I am going to start keeping track of posts like this and next time someone is ragging on me for suggesting that beginners shouldn't touch an IDE for at least a month, I'm going to have a long list of posts like this to point to. It's nothing against beginners; it's the way beginners seem to be taught that I object to :p

Last edited on
Thanks for your response, I'm really out of my element when it comes to the framework/composition behind programming. On the one hand I'm a product of the classes I've taken, but some more independent study would do me some good so I won't use my teachers as an excuse.

I'm using the Code::Blocks IDE with the "GNU GCC Compiler" selected. I'm not compiling through command line, just using Code::Block's built-in Build/Build & Run option.

All I've ever been taught with or told to use is IDE's such as this. If there's another way that would be more beneficial by all means show me the light.
Last edited on
Somewhere in your IDE is a way to put both the cpp files into the same "project" or whatever your IDE calls them.

If you're using a *nix system, that command line I gave above would do the job. Navigate to the directory containing your source code, and enter that command.
If you use an IDE it's often enough to add all the files to the same project to get linking working correctly.
I'm a little annoyed with myself that I've wasted so much effort when it was such a simple solution, but this seems to have resolved the issue. I had all the files in the same directory, but I hadn't actually set up the project in Code::Blocks.

Thanks for the responses, really helped me out of a brain-lapse.
Topic archived. No new replies allowed.