63

So I am trying to start an assignment, my professor gives us a Main.cpp, Main.h, Scanner.cpp, Scanner.h, and some other utilities.

My job is to create a Similarity class to compare documents using the cosine and Jaccard coefficients. However, I can not seem to get the project linked correctly, therefore I am unable to start on the actual code.

After trying for several hours to see what I am doing wrong, I need fresh eyes to see what I am doing wrong, I suspect it is obvious.

Here is the Main.cpp

#include "Main.h"

using namespace std;

static const string TAG = "Main: ";

int main(int argc, char *argv[])
{
  string inStreamName;
  string logStreamName;
  string outStreamName;

  ofstream outStream;
  string timeCallOutput;
  Scanner inStream;

  Similarity similarity;

  ///////////////////////////////////////////////////////////////
  // Boilerplate for naming files and opening files
  Utils::CheckArgs(3, argc, argv, "infilename outfilename logfilename");
  outStreamName = static_cast<string>(argv[2]);
  logStreamName = static_cast<string>(argv[3]);

  Utils::FileOpen(outStream, outStreamName);
  Utils::LogFileOpen(logStreamName);

  timeCallOutput = Utils::timecall("beginning");
  Utils::logStream << timeCallOutput << endl;
  Utils::logStream << TAG << "Beginning execution" << endl;

  Utils::logStream << TAG << "outfile '" << outStreamName << "'" << endl;
  Utils::logStream << TAG << "logfile '" << logStreamName << "'" << endl;
  Utils::logStream.flush();

  ///////////////////////////////////////////////////////////////
  // What follows here is the real work of this code.
  //   read the entire input file and echo it back
  //   compute the two similarity coefficients

  inStreamName = static_cast<string>(argv[1]);
  inStream.openFile(inStreamName);
  Utils::logStream << TAG << "infile '" << inStreamName << "'" << endl;
  Utils::logStream.flush();

  similarity.readData(inStream);

  outStream << TAG << "Data Begin\n" << similarity.toString() << endl;
  outStream << TAG << "Data End\n" << endl;
  outStream.flush();
  inStream.close();

  outStream << TAG << "Begin similarity computation" << endl;
  outStream << TAG << "Maximum Jaccard similarity:\n" <<
                       similarity.maxJaccard() << endl;
  outStream << TAG << "Maximum cosine similarity:\n" <<
                       similarity.maxCosine() << endl;
  outStream << TAG << "End similarity computation" << endl;
  outStream.flush();

  ///////////////////////////////////////////////////////////////
  // Boilerplate for terminating gracefully
  Utils::logStream << TAG << "Ending execution" << endl;
  timeCallOutput = Utils::timecall("ending");
  Utils::logStream << timeCallOutput << endl;
  Utils::logStream.flush();

  outStream.flush();
  Utils::FileClose(outStream);

  Utils::FileClose(Utils::logStream);

  return 0;
}

And the Main.h

#ifndef MAIN_H
#define MAIN_H

#include "../../Utilities/Utils.h"
#include "../../Utilities/Scanner.h"

#include "Similarity.h"

class Main
{
public:
  int main();
  virtual ~Main();

private:

};

#endif // MAIN_H

My Similarity.cpp

#include "Similarity.h"

using namespace std;

void readData(Scanner& inStream){
}

string maxCosine(){
    return "cosine";
}

string maxJaccard(){
    return "jaccard";
}

string toString(){
    return "toString";
}

And finally my Similarity.h:

#ifndef SIMILARITY_H
#define SIMILARITY_H

#include "../../Utilities/Scanner.h"

class Similarity
{
public:
    Similarity();
    virtual ~Similarity();

    void readData(Scanner& inStream);
    string maxCosine();
    string maxJaccard();
    string toString();
private:

};

#endif

When I use the makefile he provided, and the one I have to use in order for his script to work to grade it I get this error:

g++ -O3 -Wall -o Similarity.o -c Similarity.cpp
g++ -O3 -Wall -o Aprog Main.o Similarity.o Scanner.o ScanLine.o Utils.o 
Undefined symbols for architecture x86_64:
  "Similarity::maxJaccard()", referenced from:
      _main in Main.o
  "Similarity::readData(Scanner&)", referenced from:
      _main in Main.o
  "Similarity::toString()", referenced from:
      _main in Main.o
  "Similarity::maxCosine()", referenced from:
      _main in Main.o
  "Similarity::Similarity()", referenced from:
      _main in Main.o
  "Similarity::~Similarity()", referenced from:
      _main in Main.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [Aprog] Error 1

Thank you for reading through all that, any suggestions or solutions would be greatly appreciated.

Trevor Hutto
  • 2,112
  • 4
  • 21
  • 29

1 Answers1

72

There's no mystery here, the linker is telling you that you haven't defined the missing symbols, and you haven't.

Similarity::Similarity() or Similarity::~Similarity() are just missing and you have defined the others incorrectly,

void Similarity::readData(Scanner& inStream){
}

not

void readData(Scanner& inStream){
}

etc. etc.

The second one is a function called readData, only the first is the readData method of the Similarity class.

To be clear about this, in Similarity.h

void readData(Scanner& inStream);

but in Similarity.cpp

void Similarity::readData(Scanner& inStream){
}
Nikhil Gopal
  • 43
  • 1
  • 6
john
  • 85,011
  • 4
  • 57
  • 81
  • When I do that, I get an extra qualification on member 'Similarity'. Any thoughts there? – Trevor Hutto Sep 11 '13 at 22:03
  • Could you quote the exact error message and the code it refers to? – john Sep 11 '13 at 22:05
  • In file included from Similarity.cpp:1: Similarity.h:12: error: extra qualification ‘Similarity::’ on member ‘readData’ is the error message. – Trevor Hutto Sep 11 '13 at 22:09
  • 1
    You put `Similarity::readData` in the .cpp file not in the .h file. See edit to the answer. – john Sep 11 '13 at 22:09
  • void Similarity::readData(Scanner& inStream); string Similarity::maxCosine(); string Similarity::maxJaccard(); string Similarity::toString(); -----These are the lines it is referring to. – Trevor Hutto Sep 11 '13 at 22:10
  • @TrevorHutto You've made the wrong edit, your .h file is correct, your .cpp file is wrong. – john Sep 11 '13 at 22:13
  • Ok, to be clear, in the .h file I have 'Similarity();' and 'virtual ~Similarity();' and in the .cpp I have 'Similarity::Similarity();' and 'Similarity::~Similarity();' – Trevor Hutto Sep 11 '13 at 22:17
  • Not quite, in the .h file you have `Similarity();` and `virtual ~Similarity();`, these are *declarations* but in the .cpp file you should have *definitions* `Similarity::Similarity() { ... }` and `Similarity::~Similarity() { ... }` (you fill in the ...). – john Sep 11 '13 at 22:21
  • Thank you, it compiled. One question, what is the purpose of the Similarity:: before the definition of constructors and functions? What does it do? – Trevor Hutto Sep 11 '13 at 22:24
  • 1
    If you write in your .cpp file `string maxCosine() { ...` then the compiler doesn't know that has anything to do with the Similarity class. You say `string Similarity::maxCosine() { ...` to tell the compiler that you are talking about the maxCosine function in the Similarity class, rather than some random function that just happens to have the same name. But in the .h file `string maxCosine();` is inside `class Similarity { ... }` so the compiler knows that you are declaring a function of the Similarity class. – john Sep 11 '13 at 22:29