0

I've visited dozens of Stack Overflow posts on this and still cannot figure it out. I have a simple main.cpp file where I am trying to create a new custom object "Table." But I get a bunch of errors when trying to reference a Table object. This code works in an online compiler I've been using until now.

Errors:

[Running] cd "c:\Users\etsho\Documents\PF 2 Projects\Project 2\" && g++ main.cpp -o main && "c:\Users\etsho\Documents\PF 2 Projects\Project 2\"main
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\etsho\AppData\Local\Temp\ccjYVIOC.o:main.cpp:(.text+0x18): undefined reference to `Table::Table()'
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\etsho\AppData\Local\Temp\ccjYVIOC.o:main.cpp:(.text+0x42): undefined reference to `Table::~Table()'
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\etsho\AppData\Local\Temp\ccjYVIOC.o:main.cpp:(.text+0x55): undefined reference to `Table::~Table()'
collect2.exe: error: ld returned 1 exit status

main.cpp:

#include <iostream>
#include "table.h"

using namespace std;

int main()
{
   //initialize variables
   Table table;

   return 0;
}

table.h:

#ifndef TABLE_H
#define TABLE_H
#include "person.h"
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include <regex>
using namespace std;

class Table
{
public:
   // Constructor methods
   Table();
   Table(const Table & table);
   ~Table();

   // Input output methods
   void Print() const;
   void Read(const string fileName);

   // Searching methods
   void searchFirstName(string firstName);
   void searchLastName(string lastName);
   void searchYear(string yearRange);
   
   // Other methods
   void printTable(vector<Person> printPeople) const;

private:
   // Object attributes
   vector<Person> people;
};
#endif

table.cpp:

#include "table.h"

//Constructor
Table::Table()
{
}

//Destructor
Table::~Table()
{
}

//-------
//Input output methods
//-------
void Table::Print() const
{
   //print all people
   printTable(people);
}

void Table::Read(const string fileName)
{
   // Open input file
   ifstream din;
   din.open(fileName.c_str());
   if (din.fail()){
      cout << "Error: could not open file\n";
      return;
   }  
   
   // Read people information
   Person person;
   string line = "";
   while (getline(din, line)){
      int personReadCount = 0;
      
      //split string by space
      vector<string> words;
      istringstream iss(line);
      for (string s; iss >> s; ){
         words.push_back(s);
      }
      
      //set person's attributes
      person.setFirstName(words[0]);
      person.setLastName(words[1]);
      person.setBirthYear(stoi(words[2]));
      person.setDeathYear(stoi(words[3]));
      person.setContribution("");
      for (int loop = 4; loop < words.size(); loop++){
         person.setContribution(person.getContribution() + " " + words[loop]);
      }
      
      people.push_back(person);
   }
}

//-------
//Searching methods
//-------
void Table::searchFirstName(string firstName)
{
   vector<Person> newList;
   transform(firstName.begin(), firstName.end(), firstName.begin(), ::toupper);
   for (int loop = 0; loop < people.size(); loop++){
      string newFirstName = people[loop].getFirstName();
      transform(newFirstName.begin(), newFirstName.end(), newFirstName.begin(), ::toupper);
      if (newFirstName == firstName)
         newList.push_back(people[loop]);
   }
   
   printTable(newList);
}

void Table::searchLastName(string lastName)
{
   vector<Person> newList;
   transform(lastName.begin(), lastName.end(), lastName.begin(), ::toupper);
   for (int loop = 0; loop < people.size(); loop++){
      string newLastName = people[loop].getLastName();
      transform(newLastName.begin(), newLastName.end(), newLastName.begin(), ::toupper);
      if (newLastName == lastName)
         newList.push_back(people[loop]);
   }
   
   printTable(newList);
}

void Table::searchYear(string yearRange)
{
   vector<Person> newList;
   transform(yearRange.begin(), yearRange.end(), yearRange.begin(), ::toupper);
   for (int loop = 0; loop < people.size(); loop++){
      string yearFormat = to_string(people[loop].getBirthYear()) + "-" + to_string(people[loop].getDeathYear());
      if (people[loop].getDeathYear() == -1)
         yearFormat = regex_replace(yearFormat, regex("-1"), "PRESENT");
      transform(yearFormat.begin(), yearFormat.end(), yearFormat.begin(), ::toupper);
      cout << yearRange << " " << yearFormat << endl;
      if (yearFormat == yearRange)
         newList.push_back(people[loop]);
   }
   
   printTable(newList);
}

//-------
//Other methods
//-------
void Table::printTable(vector<Person> printPeople) const
{
   //print out attributes of people in vector
   cout << "\nFirstName LastName, BirthYear-DeathYear, Contribution" << endl;
   for (int loop = 0; loop < printPeople.size(); loop++){
      cout << printPeople[loop].getFirstName() << " " << printPeople[loop].getLastName()
         << ", " << printPeople[loop].getBirthYear() << "-";
      if (printPeople[loop].getDeathYear() == -1){
         cout << "Present";
      }
      else{
         cout << printPeople[loop].getDeathYear();
      }
      cout << "," << printPeople[loop].getContribution() << endl;
   }
   
   if (printPeople.size() == 0)
      cout << "No results" << endl;
}

Any help is appreciated. Thanks.

Ethan Shoe
  • 466
  • 1
  • 7
  • 20
  • This can not be tested without "person.h". You can typically do a minimal reproducible in just one .cpp file. Please post that. – lakeweb Feb 11 '22 at 03:37
  • 2
    These are linker errors, telling you the linker doesn't know where you defined those functions. No surprise, since they don't exist in `main.cpp`. You're only compiling `main.cpp`, not `table.cpp`. The linker needs both. Change your one-shot compilation command to `g++ main.cpp table.cpp -o main` – paddy Feb 11 '22 at 03:40
  • 2
    As an aside, please don't put `using namespace std;` in your header files. It will cause you pain sooner or later. Preferably, don't use that anywhere. – paddy Feb 11 '22 at 03:42
  • @paddy just curious, why not use ```using namepace std``` ever? My professor says to use it. Thanks. – Ethan Shoe Feb 11 '22 at 03:52
  • 1
    [Why is "using namespace std;" considered bad practice?](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) – Drew Dormann Feb 11 '22 at 03:59
  • Importing the entire `std` namespace just because you're using a few containers works okay for toy programs like yours, but in production codebases where you deal with hundreds of thousands of code lines, multiple libraries and high complexity, laziness like this can be disastrous. It's a good habit to avoid. If you choose to do it anyway, at least always be mindful of doing it: "oh yeah, I'm doing this and it's fine here". – paddy Feb 11 '22 at 04:00
  • @paddy so it's bad because it slows stuff down? – Ethan Shoe Feb 11 '22 at 04:01
  • 2
    No. Follow the link posted by Drew. – paddy Feb 11 '22 at 04:01

0 Answers0