0

I'm new to this multi-file class stuff and I've got an undefined reference for both of my classes and I think it has something to do with my initialization and default constructor but honestly have no clue if any of this is correct at all. Any help is greatly appreciated.

main.cpp

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

int main() {
   string userTitle, userArtistName;
   int yearCreated, userBirthYear, userDeathYear;

   getline(cin, userArtistName);
   cin >> userBirthYear;
   cin.ignore();
   cin >> userDeathYear;
   cin.ignore();
   getline(cin, userTitle);
   cin >> yearCreated;
   cin.ignore();

   Artist userArtist =  Artist(userArtistName, userBirthYear, userDeathYear);

   Artwork newArtwork = Artwork(userTitle, yearCreated, userArtist);

   newArtwork.PrintInfo();
}

Artist.h

#ifndef ARTISTH
#define ARTISTH

#include <string>
using namespace std;

class Artist{
   public:
      Artist();

      Artist(string artistName, int birthYear, int deathYear);

      string GetName() const;

      int GetBirthYear() const;

      int GetDeathYear() const;

      void PrintInfo() const;

   private:
      string artistName;
      int birthYear;
      int deathYear;

};

#endif

Artist.cpp

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

Artist::Artist()
{
   artistName = "unknown";
   birthYear = -1;
   deathYear = -1;
}



string Artist::GetName() const 
{
   return artistName;   
}

int Artist::GetBirthYear() const
{
   return birthYear;   
}

int Artist::GetDeathYear() const
{
   return deathYear;
}

void Artist::PrintInfo() const
{
   if(deathYear > 0 && birthYear > 0)
   {
   cout << "Artist: " << artistName <<" ("<< birthYear << " to "<< deathYear << ")" << 
endl;   
   }
   else if(birthYear > 0 && deathYear < 0)
   {
   cout << "Artist: " << artistName <<" ("<< birthYear << " to present)" << endl;  
   }
   else if(birthYear<0 && deathYear<0)
   {
   cout << "Artist: " << artistName << " (unknown)" << endl;  
   }
}

Artwork.h

#ifndef ARTWORKH
#define ARTWORKH

#include "Artist.h"

class Artwork{
   public:
      Artwork();

      Artwork(string title, int yearCreated, Artist artist);

      string GetTitle();

      int GetYearCreated();

      void PrintInfo();

   private:
      string title;
      int yearCreated;
  
      Artist artist;

};

#endif

Artwork.cpp

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

Artwork::Artwork()
{
   cout <<"Artwork has started." << endl;
   title = "unknown";
   yearCreated = -1;
   Artist artist(); //here im not sure how to initialize an object inside of an object
}


string Artwork::GetTitle()
{
   return title;   
}

int Artwork::GetYearCreated()
{
   return yearCreated;   
}

void Artwork::PrintInfo()
{
   artist.PrintInfo();
   cout << "Title: " << title << ", " << yearCreated << endl;

}
Dax
  • 1
  • 2
  • 1
    Are you using cmake? – Angelos Gkaraleas Sep 23 '22 at 23:05
  • 1
    Seek ye the [Member Initializer List](https://en.cppreference.com/w/cpp/language/constructor) – user4581301 Sep 23 '22 at 23:06
  • no its in a zybooks lab so im sure its not a compiling error – Dax Sep 23 '22 at 23:07
  • I can't wrap my brain around the member initializer list since i have to use multiple files – Dax Sep 23 '22 at 23:08
  • 2
    Actually in your cpp files you missed to define 'Artist(string artistName, int birthYear, int deathYear);' – Angelos Gkaraleas Sep 23 '22 at 23:09
  • Side note: `Artist artist();` is a declaration of a function named `artist` that returns an `Artist`. `Artist artist{};` would be the definition of a local variable named `artist` that is a `Artist` and is totally unconnected to the `artist` member variable. To initialize a member inside a class, you're going to have to get the member initiallizer list figured out. It's that or default initialization. See both in action here: https://en.cppreference.com/w/cpp/language/data_members#Member_initialization – user4581301 Sep 23 '22 at 23:12
  • 1
    `Artist.cpp` is missing a *definition* of the `Artist(string, int, int)` constructor, and `Artwork.cpp` is missing a *definition* of the `Artwork(string, int, Artist)` constructor. `main()` is using both of them, but the linker can't find their implementations, hence the errors. – Remy Lebeau Sep 23 '22 at 23:16

1 Answers1

0

I was correct, i needed to initialize both a default(no input parameters) constructor and a constructor with input parameters.

to correctly write a default and parameter constructor, do this

Artwork::Artwork(string n, int y, Artist a)
{
   title = n;
   yearCreated = y;
   artist = a;
}//constructor with given input

Artwork::Artwork()
{
   title = "unknown";
   yearCreated = -1;
}//if input is not given for any fields, refer to this constructor

Notice that the default constructor does not have an object, I'm honestly not sure if there is a way to initialize a blank object and if so, why that isn't necessary.

The Artist constructor looks the same,

Artist::Artist(string name, int birth, int death)
{
   artistName = name;
   birthYear = birth;
   deathYear = death;
}

Artist::Artist()
{
   artistName = "unknown";
   birthYear = -1;
   deathYear = -1;
}
Dax
  • 1
  • 2
  • Suggestion: Instead of assigning in the body of the default constructor, use default initialization. Up in `Artist`'s class definition replace `string artistName;` with `string artistName;`. – user4581301 Sep 24 '22 at 00:56
  • In general avoid performing assignments in the constructor body because by then the variable has already been initialized and if that initialization is expensive, that's just time wasted. When you `artistName = name;`, `artist` had just been set to its default value and now you're writing over it, but `Artist::Artist(string name, int birth, int death): artistName(name) {` uses the member initializer to construct the `string` with the correct value immediately. Everybody wins. – user4581301 Sep 24 '22 at 00:56