Hello,

It seems like every time I start a new project with classes I have trouble with this.

I am getting an error "undefined reference to 'Item::Item()'

I'm sure I am overlooking a simple mistake. I have been looking at this for an hour and I cannot seem to find a problem with my code.

#include "utility.h"
#include "Item.h"
using namespace std;


int main()
{
	cout << "beginning" << endl;

	Item test;

	cout << "middle" << endl;

	test.makeItem(3, "Dallas");

    cout << "end" << endl;

}
#ifndef UTILITY_H
#define UTILITY_H

//Gives ANSI version of standard includes
//Also defines enumerated type for error
//messages 

#include <iostream>
#include <limits>
#include <cmath>
#include <cstdlib>
#include <cstddef>
#include <fstream>
#include <cctype>
#include <ctime>
#include <string>

using namespace std;


enum Error_code { success, fail, exceeds_range, 
not_present, duplicate_error, underflow, overflow };

#endif //UTILITY_H
#ifndef ITEM_H
#define ITEM_H

class Item
{
public:

void makeItem(int arrival, string dest);


private:
	int arrivalTime;
	string destination;
};

#endif // ITEM_H
#include "utility.h"
#include "Item.h"

/*
Item::Item()
{
}// End constructor

Item::~Item()
{
}// End destructor
*/

void Item::makeItem(int arrival, string dest)
{
	arrivalTime = arrival;
	destination = dest;
}// End makeItem

I presume you are getting your error when lines 4 through 12 of Item.cpp are uncommented?

You cannot just add methods to a class. You need to prototype them along with the class.

class Item
{
public:
	Item();
	~Item();
	void makeItem(int arrival, string dest);


private:
	int arrivalTime;
	string destination;
};

BTW, you are doing a couple of unkosher and dangerous things.

Don't using namespace [i]anything[/i] in header files. It isn't up to you what to stick in the user's global namespace. (Even if you are your own user.)

Stick the appropriate #include directives in the same header file as needed. For example, your "Item.h" file should look like:

#pragma once
#ifndef ITEM_H
#define ITEM_H

#include <string>

class Item
{
...
};

#endif

I won't bug you here about namespaces, but you should have your stuff wrapped in a namespace also...

You shouldn't have files lying around just to #include all kinds of other files.

Finally, your makeItem() method seems to be doing the job of the constructor. Why not just have the constructor do it?

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

int main()
{
	cout << "beginning" << endl;

	Item item(3, "Dallas");

	cout << "end" << endl;

	return 0;
}

Hope this helps.

#ifndef ITEM_H
#define ITEM_H
 
class Item
{
public:
 Item();
~Item();
void makeItem(int arrival, string dest);
 
 
private:
	int arrivalTime;
	string destination;
};
 
#endif // ITEM_H

The original problem is that with the constructor and destructor source missing from the class prototype, and commented out in the implementation, there was no way for your line 10 to work: Item test; . In order for the compiler to create a default instance of your class, there must be a constructor (even if it's empty and doesn't do anything). And there really should be a destructor, even if it doesn't need to destroy anything else for you. (note: "really should" might turn out to be "must" also.)

Thanks guys. It is working now.

Is this the correct way to use an accessor (getter) function? I am concerned that the way I have declared "arrival" in the Item.cpp file makes it a public variable.


main.cpp

#include "utility.h"
#include "Item.h"
using namespace std;


int main()
{
	cout << "beginning" << endl;

	Item test;
	test.makeItem(3, "Dallas");
    cout << test.getArrival();
    cout << "end" << endl;
}

Item.cpp

#include "utility.h"
#include "Item.h"

int arrival;    // Is it still private if I declare here?

void Item::makeItem(int x, string y)
{
    arrival = x;
    dest = y;
}

int Item::getArrival()
{
    return arrival;
}

Item.h

#ifndef ITEM_H
#define ITEM_H

class Item
{

public:
    void makeItem(int x, string y);
    int getArrival();
    int getDestination();

private:
    int arrival;
    string dest;
};

#endif // ITEM_H

Edited 5 Years Ago by coolbeanbob: n/a

The original problem is that with the constructor and destructor source missing from the class prototype, and commented out in the implementation, there was no way for your line 10 to work: Item test; .

Not so. If you don't provide a ctor, the compiler is required to create a default one for you.

Is this the correct way to use an accessor (getter) function?

Yes. However, your getter methods should be const: int getArrival() const;

I am concerned that the way I have declared "arrival" in the Item.cpp file makes it a public variable.

It doesn't matter because you shouldn't be doing this. Line 4 of Item.cpp creates a different variable than the one on line 13 of Item.h. Get rid of that line 4 and you should be fine.


A common thing to do is to have the both the ctor and the assignment operator call a common setter method. For example:

Item(int x = 0, string y = string()) { makeItem(x, y); }

BTW, "x" and "y" are not very descriptive names. You should name them like you originally had.

Also, your makeItem() should take a const reference string: void makeItem(int arrival_time, const string& destination_name) Hope this helps.

Not so. If you don't provide a ctor, the compiler is required to create a default one for you.

While that sounds vaguely familiar now that you remind me, how did the OP get the originally reported error?

I am getting an error "undefined reference to 'Item::Item()'

Or is the problem that he got the error when he uncommented the empty implementations in his Item.cpp, without explicitly adding them to his Item.h? While apparently not necessary, I -always- include a constructor (at least one, even if it's empty) and destructor in my classes, so I haven't run into an issue like this. Thanks for the clarification, after 20+ years, I'm always learning something here!

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