Template Class problems.

Hello everyone!

I've practicing for an exam today and I have encountered a few problems that I couldn't solve on my own. Here is what I am meant to do, so you can easier understand my problem.

In this program, I have to create a template class called Collection and classes named Hotel and Restaurant. The class Collection must have a few public methods:

- Find (a method that checks if the forwarded element is the same as any of the elements in an array)
- Arrange (a method that arranges elements of an array into descending order)
- Reverse (a method that inverts an array)
- Set (a method that sets an element into desired place in an array).

In Hotel and Restaurant classes I must make all necessary public methods so these classes can be used in template class Collection.

Here is what I've done so far and after the code you can read some concrete questions that I have to ask.

COLLECTION.H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include<iostream>
using namespace std;

template<class T, int numberOfElements>
class Collection
{
private:
	T *array;
public:
	Collection();
	~Collection();
	bool Find(T &t); // Function that returns TRUE if "t" is equal to any element of an array.
	void Arrange(); // Function that arranges an array into descending order.
	void Reverse(); // Function that inverts an array.
	void Set(T &t, int index); // Function that sets the forwarded element in a prorper position in an array.
};


/* Find(T &t) FUNCTION */
template<class T, int numberOfElements>
bool Collection<T, numberOfElements>::Find(T &t)
{
	int found = 0;
	for (int i = 0; i < numberOfElements; i++)
	{
		if (t != array[i])
		else
		found = found + 1;
	}

	if (found > 0)
		return true;
	else
		return false;
}

/* Arrange() FUNCTION */
template<class T, int numberOfElements>
void Collection<T, numberOfElements>::Arrange()
{
	for (int i = 0; i < numberOfElements; i++)
	{
		for (j = i + 1; j < numberOfElements - 1; j++)
		{
			if (array[i] < array[j])
			{
				T temp = array[i];
				array[i] = array[j];
				array[j] = temp;
			}
		}
	}
}

/* Reverse() FUNCTION */
template<class T, int numberOfElements>
void Collection<T, numberOfElements>::Reverse()
{
	for (int i = 0; i < numberOfElements / 2; i++)
		for (int j = numberOfElements - 1; j > numberOfElements / 2; j--)
		{
			T temp = array[i];
			array[i] = array[j];
			array[j] = array[i];
		}
}


/* Set(T &t, int index) FUNCTION */
template<class T, int numberOfElements>
void Collection<T, numberOfElements>::Set(T &t, int index)
{
	if (index<0 || index>numberOfElements)
	{
		array[index] = t;
	}
	throw "Index value is invalid.";
}


HOTEL.H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#pragma once
#include<iostream>
using namespace std;

class Hotel
{
private:
	char *hotelName;
	int openingYear;
	int category;
	int numberOfRooms;
public:

	Hotel()
		:hotelName(""), openingYear(0), category(0), numberOfRooms(0) {};

	Hotel(char *name, int year, int rank, int number)
		:hotelName(name), openingYear(year), category(rank), numberOfRooms(number) {};

	~Hotel();

	int returnCategory() { return category; }
	int returnNumberOfRooms() { return numberOfRooms; }

	friend istream& operator>>(istream& in, Hotel &h)
	{
		return in >> h.hotelName >> h.openingYear >> h.category >> h.numberOfRooms;
	}

	friend ostream& operator<<(ostream& out, Hotel &h)
	{
		return out << "Hotel name: " << h.hotelName << "\n"
			<< "Opening year: " << h.openingYear << "\n"
			<< "Category: " << h.category << "\n"
			<< "Number of rooms: " << h.numberOfRooms << endl;
	}

	Hotel &operator=(Hotel &h)
	{
		hotelName = h.hotelName;
		openingYear = h.openingYear;
		category = h.category;
		numberOfRooms = h.numberOfRooms;
                return *this
	}
};


RESTAURANT.H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#pragma once
#include<iostream>
using namespace std;

class Restaurant
{
private:
	char *restaurantName;
	int openingYear;
	int numberOfSeats;
public:

	Restaurant()
		:restaurantName(""), openingYear(0), numberOfSeats(0) {};

	Restaurant(char *name, int year, int seats)
		:restaurantName(name), openingYear(year), numberOfSeats(seats) {};

	~Restaurant();

	int returnNumberOfSeats() { return numberOfSeats; }

	friend istream& operator>>(istream& in, Restaurant &r)
	{
		return in >> r.restaurantName >> r.openingYear >> r.numberOfSeats;
	}

	friend ostream& operator<<(ostream &out, Restaurant &r)
	{
		return out << "Restaurant name: " << r.restaurantName << "\n"
			<< "Opening year: " << r.openingYear << "\n"
			<< "Number of seats: " << r.numberOfSeats << endl;
	}

	Restaurant &operator=(Restaurant &r)
	{
		restaurantName = r.restaurantName;
		openingYear = r.openingYear;
		numberOfSeats = r.numberOfSeats;
                return *this
	}
};


1st problem: The method Arrange that I have in my template class is supposed to arrange an array into descending order. If I forward an array of type Hotel, it should be arranged into descending order by category or number of rooms, and if I forward an array of type Restaurant, it should be arranged into descending order by a number of seats. Any suggestions on how I might do this?

2nd problem: In my main.cpp I want to specialize a template for integers, Hotels and Restaurants and test all the methods from my Collection class.
Testing the methods is not hard but I'm a little confused about creating the constructors in template class. I guess that is why it won't work, but I really don't know how to do constructors here. Any suggestions?

I have tried this:

1
2
3
4
5
6
7
8
9
10
11
12
Hotel Hotel1("Grand Hotel" , 1900, 5 , 200);
Hotel Hotel2("NotSoGrand Hotel", 1900, 1, 50);
Restaurant Restaurant1("Bernie's Place", 1919, 25);
Restaurant Restaurant2("At Joe's", 1920, 20);

Collection<Hotel,2>Hotels;
Hotels.Set(Hotel1, 0);
Hotels.Set(Hotel2, 1);

Collection<Restaurant,2>Restaurants;
Restaurants.Set(Restaurant1, 0);
Restaurants.Set(Restaurant2, 1);


After writing this in my main.cpp I get a lot of errors:

Error 7 error LNK1120: 6 unresolved externals

Error 4 error LNK2019: unresolved external symbol "public: __thiscall Collection<class Hotel,2>::~Collection<class Hotel,2>(void)" (??1?$Collection@VHotel@@$01@@QAE@XZ) referenced in function _main

Error 3 error LNK2019: unresolved external symbol "public: __thiscall Collection<class Hotel,2>::Collection<class Hotel,2>(void)" (??0?$Collection@VHotel@@$01@@QAE@XZ) referenced in function _main

Error 6 error LNK2019: unresolved external symbol "public: __thiscall Collection<class Restaurant,2>::~Collection<class Restaurant,2>(void)" (??1?$Collection@VRestaurant@@$01@@QAE@XZ) referenced in function _main

Error 5 error LNK2019: unresolved external symbol "public: __thiscall Collection<class Restaurant,2>::Collection<class Restaurant,2>(void)" (??0?$Collection@VRestaurant@@$01@@QAE@XZ) referenced in function _main

Error 1 error LNK2019: unresolved external symbol "public: __thiscall Hotel::~Hotel(void)" (??1Hotel@@QAE@XZ) referenced in function _main

Error 2 error LNK2019: unresolved external symbol "public: __thiscall Restaurant::~Restaurant(void)" (??1Restaurant@@QAE@XZ) referenced in function _main


I know this is a long post but I wanted to provide all the details.
Also, this is not an assignment that I have for my college, it's just a problem that I'm trying to figure out so I can be prepared for an exam.



EDITED: Here is the text of what I should do:

Create a template class Collection that has an array of elements of any type as its private member whose number of elements is a template parameter of type int.
Create the following public methods:
1)Function Find that checks if the forwarded element is equal to any of the elements in Collection using operator !=
2)Function Arrange that arranges all the elements of an array into descending order.
3)Function Reverse that inverts an array.
4)Function Set that sets the element to a proper place(index) in array.

Create a class Hotel whose private members are name, opening year, category and number of rooms and create all public methods so that this class can be used for specialization in template class. When arranging the hotels, arrange them by category or number of rooms.

Create a class Restaurant whose private members are name, opening year and number of seats and create all public methods so that this class can be used for specialization in template class. When arranging the restaurants, arrange them by number of rooms.

Excuse me if my english is not so good, I have translated this on my own and I hope that you will understand enough to help me solve this problem.
Last edited on
1st:
You should define operator !=and operator<for Restaurant and Hotel.
1
2
3
4
friend bool operator<(Hotel const&lhs,Hotel const&rhs)
{
    return lhs.numberOfRooms<rhs.numberOfRooms;
}

1
2
3
4
friend bool operator<(Restaurant const&lhs,Restaurant const&rhs)
{
    return lhs.numberOfSeats<rhs.numberOfSeats;
}

2nd:One way is like this.
1
2
3
4
5
6
7
8
9
10
template<class T, int numberOfElements>
Collection::Collection()
{
    array=new T[numberOfElements];
}
Collection::~Collection()
{
    delete [] array;
    array=nullptr;
}

But I think that a better way is to change array into an array:
T array[numberOfElements];
1) what should this do?
1
2
3
if (t != array[i])
		else
		found = found + 1;


if you only want to do something if t == array[i] then negate it or use operator==
1
2
if (t == array[i])
    found = found + 1;

1
2
if (!(t != array[i]))
    found = found + 1;


2) this function should set the value if the index is between 0 and numberofelements, you do the exact opposite
You ask, if the index is smaller than 0 or greater than numberOfElements.
This means that the index is not in between 0 and numberOfElements.
1
2
3
4
5
6
7
8
9
10
/* Set(T &t, int index) FUNCTION */
template<class T, int numberOfElements>
void Collection<T, numberOfElements>::Set(T &t, int index)
{
	if (index<0 || index>numberOfElements)
	{
		array[index] = t;
	}
	throw "Index value is invalid.";
}

you should negate the whole if statement:
if (!(index<0 || index>numberOfElements))

3) you should make array an array and not a pointer
you know the size at compile time so there is no need to make a pointer
T array[numberOfElements];

4) you have to implement the operators like while said

5)
2nd problem: In my main.cpp I want to specialize a template for integers, Hotels and Restaurants and test all the methods from my Collection class.


This WON'T work.
a cpp file will be compiled only in this translation-unit and template-classes must be available in all translation-units.
You have to write the class in a seperate file and then include this and you must not compile it, just include it.

6) linking errors
Error 7 error LNK1120: 6 unresolved externals

Error 4 error LNK2019: unresolved external symbol "public: __thiscall Collection<class Hotel,2>::~Collection<class Hotel,2>(void)" (??1?$Collection@VHotel@@$01@@QAE@XZ) referenced in function _main

Error 3 error LNK2019: unresolved external symbol "public: __thiscall Collection<class Hotel,2>::Collection<class Hotel,2>(void)" (??0?$Collection@VHotel@@$01@@QAE@XZ) referenced in function _main

Error 6 error LNK2019: unresolved external symbol "public: __thiscall Collection<class Restaurant,2>::~Collection<class Restaurant,2>(void)" (??1?$Collection@VRestaurant@@$01@@QAE@XZ) referenced in function _main

Error 5 error LNK2019: unresolved external symbol "public: __thiscall Collection<class Restaurant,2>::Collection<class Restaurant,2>(void)" (??0?$Collection@VRestaurant@@$01@@QAE@XZ) referenced in function _main

Error 1 error LNK2019: unresolved external symbol "public: __thiscall Hotel::~Hotel(void)" (??1Hotel@@QAE@XZ) referenced in function _main

Error 2 error LNK2019: unresolved external symbol "public: __thiscall Restaurant::~Restaurant(void)" (??1Restaurant@@QAE@XZ) referenced in function _main 


you didn't provide an implementation for these functions:
1
2
3
4
Collection();
~Collection();
~Hotel();
~Restaurant();


you should just erase those lines, the compiler will create those methods by default
Note that you should use an T array[numberOfElements] so that the compiler knows how to handle the constructor and destructor of collection automatically, otherwise you might have problems with the default constructor and destructor.
Last edited on
@Gamer2015

1) In the text it says that I must use overloaded != function in order to find if there is the same element in an array.

2)
1
2
3
4
5
6
7
8
9
10
/* Set(T &t, int index) FUNCTION */
template<class T, int numberOfElements>
void Collection<T, numberOfElements>::Set(T &t, int index)
{
	if (index<0 || index>numberOfElements)
	{
		array[index] = t;
	}
	throw "Index value is invalid.";
}


Here I only wanted to throw an exception if index is a negative number or when index is higher than numberOfElements.

3) I have corrected this and will try using it.

4) I have tried implementing the operators != in Hotel and Restaurant, this is what I came with:

HOTEL
1
2
3
4
5
6
7
bool Hotel::operator!=(Hotel &h)
	{
		if (hotelName == h.hotelName && openingYear == h.openingYear && category == h.category && numberOfRooms == h.numberOfRooms)
			return false;
		else
			return true;
	}


RESTAURANT - I have an error, can't find the mistake (Error 2 error C2106: '=' : left operand must be l-value) only restaurantName is underlined with red.
1
2
3
4
5
6
7
bool Restaurant::operator!=(Restaurant &r)
	{
		if (restaurantName == r.restaurantName && openingYear == r.openingYear && numberOfSeats = r.numberOfSeats)
			return false;
		else
			return true;
	}



5) I'm not really sure right now how should I do this.

6) COLLECTION I have implemented these, the linking errors are gone but there is still error from 4)

1
2
3
4
5
6
7
8
9
10
11
12
13
/* DEFAULT CONSTRUCTOR */
template<class T, int numberOfElements>
Collection<T, numberOfElements>::Collection()
{
	array = new T[numberOfElements];
}

/* DESTRUCTOR */
template<class T, int numberOfElements>
Collection<T, numberOfElements>::~Collection()
{
	delete[] array;
}



I have also edited my first text in this post and updated it with the translated version of the problem, it is at the bottom of my first text.
Last edited on
In 4 you're using a = where you should be using a ==
1) In the text it says that I must use overloaded != function in order to find if there is the same element in an array.

then negate the result

2) Here I only wanted to throw an exception if index is a negative number or when index is higher than numberOfElements.

then the code is wrong and needs to be negated

5) I'm not really sure right now how should I do this.

I don't understand why you even want to make a spezialisation for int
you can just use Collection<int, 200> anyway
Nevermind. I have fixed 1) and 2) and I'm working on 5), I think it will work this time. :)
Topic archived. No new replies allowed.