Whenever I try to compile my Song class I get a ton of linker error messages. I'm using the Dev-C++ compiler. Here's my code:

//The header file

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>

using namespace std;

class Song
{
public: 
        Song();
		Song(string title, string artist, string album);
		void setTitle(string aTitle);       
        void setArtist(string anArtist);
        void setAlbum(string anAlbum);
        string getTitle();      //to get the Song Title
        string getArtist();     //to get artist name
        string getAlbum();      //to get album name
		bool operator==(const Song & otherSong);
		bool operator>(const Song & otherSong);
		string displayString();
private: 
        string songTitle;
        string artistName;
        string albumName;
 };

//The implementation file

#include <string>
#include <iostream>
#include "Song.h" 
 
using namespace std;

Song::Song(){
	songTitle = "";
	artistName = "";
	albumName = "";
}

Song::Song(string title, string artist, string album){
	songTitle = title;
	artistName = artist;
	albumName = album;
}

void Song::setTitle(string aTitle){
	songTitle = aTitle;
}

void Song::setArtist(string anArtist){
    artistName = anArtist;
}

void Song::setAlbum(string anAlbum){
    albumName = anAlbum;
}

string Song::getTitle()
{
     return songTitle;
}
string Song::getArtist()
{
     return artistName;
}
string Song::getAlbum()
{                
     return albumName;
}     

bool Song::operator==(const Song & otherSong){
 bool status;
 if(songTitle == otherSong.songTitle && artistName == otherSong.artistName && albumName == otherSong.albumName)
        status = true;     //to see if songs are equal 
 else
        status = false;
 
 return status;              
}

bool Song::operator>(const Song & otherSong){
bool status;
}

if(albumName > otherSong.albumName)
       status = true;    //to compare songs lexicographically 
else if(albumName == otherSong.albumName && songTitle > otherSong.songTitle)
       status = true;   //if album is the same, sort by song 
  
return status;                    
}

string Song::displayString(){
    string result = "\nTitle:  " + songTitle;
	result += "\nArtist:  " + artistName;
	result += "\nAlbum:  "  + albumName;
	return result;
}

Edited 5 Years Ago by MarginOfBuffett: n/a

What are the errors exactly? Make sure you include safe guards in the header file. For example :

#ifndef SONG_H
#define SONG_H
class Song{...}
#endif

Edited 5 Years Ago by firstPerson: n/a

Here are the compiler errors:

[Linker error] undefined reference to `FileReaderWriter::FileReaderWriter()' 
  [Linker error] undefined reference to `Song::Song()' 
  [Linker error] undefined reference to `Song::setTitle(std::string)' 
  [Linker error] undefined reference to `Song::setArtist(std::string)' 
  [Linker error] undefined reference to `Song::setAlbum(std::string)' 
  [Linker error] undefined reference to `Song::displayString()' 
  [Linker error] undefined reference to `Song::displayString()' 
  [Linker error] undefined reference to `Song::Song()' 
  [Linker error] undefined reference to `Song::Song()'

What are the errors exactly? Make sure you include safe guards in the header file. For example :

#ifndef SONG_H
#define SONG_H
class Song{...}
#endif

Why not $pragma once instead?

@OP: Most probably the issue is you're not linking your client's .o file with Song.o while linking.
If you're compiling and linking separately know what you're doing.
Simplest way to understand is to export a makefile from the IDE you're using and read it.

Why not $pragma once instead?

@OP: Most probably the issue is you're not linking your client's .o file with Song.o while linking.
If you're compiling and linking separately know what you're doing.
Simplest way to understand is to export a makefile from the IDE you're using and read it.

Usually the suggestion is to use both pragma once and include guards, so that it is portable and also allows the possibility of compiler optimization. I just said include guards just because.

Usually the suggestion is to use both pragma once and include guards, so that it is portable and also allows the possibility of compiler optimization. I just said include guards just because.

Indeed. #pragm directives are incredibly non-portable. You absolutely MUST guard them in all but possibly a few common cases. In fact, #pragma directives are specifically intended to allow different compilers and platforms to tweak behavior in very personal ways. They are definitely NOT intended for general programming use.

Do all compilers support it?

A better question is "do all compilers that matter for your project support it?".

Usually the suggestion is to use both pragma once and include guards

What happens if the compiler supports #pragma once but it doesn't do the same thing? That's somewhat unlikely, but the potential exists. Inclusion guards always work in a conforming compiler.

Indeed. #pragm directives are incredibly non-portable.

They're non-portable by definition. Let's be honest for a moment and recognize that a lot of software has no need for portability beyond easing upgrades to newer versions of the same compiler, and if you need to be portable to a compiler that doesn't support it, you're probably good enough to know how to deal with it. If #pragma performs a function that can't be done portably, or you don't give two shits about being portable, go for it.

However, wise programmers will typically cringe at the thought of using a non-portable construct when a portable equivalent exists.

They are definitely NOT intended for general programming use.

There are two issues with inclusion guards that #pragma once solves:

  • Inclusion guards require a unique symbol for each and every header. The preprocessor doesn't have an equivalent to namespaces, so we're back to the old school nightmare of name conflicts with ugly solutions. #pragma once doesn't require a symbol to be defined.
  • With inclusion guards, the preprocessor still needs to parse the header for every #include directive. This can increase compilation time. #pragma once avoids the parsing issue and can improve compilation time.

These are very real issues that show up in general programming. It's up to the programmer to decide if those two issues are significant enough to justify using a less portable method for idempotent headers.

>>What happens if the compiler supports #pragma once but it doesn't do the same thing? That's somewhat unlikely, but the potential exists. Inclusion guards always work in a conforming compiler.

What other things can it do that would affect it in a bad way? And isn't pragma once supported by major compilers?

What other things can it do that would affect it in a bad way?

Pragmas are completely implementation-dependent. As I said, very unlikely, but the possibility exists for a pragma to be interpreted differently. Kind of like if you do system("pause") and the system supports a pause program, but it doesn't do the same thing as the Windows pause program.

And isn't pragma once supported by major compilers?

It's widely supported, though some major compilers (GCC, for example) have deprecated it.

This article has been dead for over six months. Start a new discussion instead.