Hi, I have created a generic linked list in which different objects can be added to a list as long as they inherit from my object class. My problem is this:
I am able to add nodes and find nodes etc. but I can't figure out how to return an instance of an Object which has been added.
Below shows the code I am having trouble with (although there are many different instances of this problem, they can hopefully be resolved through this one instance being solved):

int Bank::customerSearch(unsigned int custNum)
{
	int i;
	for(i = 0; i < theCustomers.size(); ++i)
	{
		Customer c = theCustomers.at(i); //here is my problem
		if(c.getCustNum() == custNum)
		{
			return i;
		}
	}
	return -1;
}

When I try to assign the customer instance my program breaks because in my list the at() function is currently returning an Object reference as opposed to a Customer reference. I need to somehow return a reference to a Customer (or Account or Mortgage) instead so that it works similar to the at() function in a vector.

I have attached the header file and cpp file that I use for my linked list.

Thanks

Edited 7 Years Ago by Valaraukar: n/a

Attachments
#include "myList.h"

void List::add(Object &newNode)
{
	Node *newElement = new Node(&newNode);

	if(head != 0)//if there is already a node just add item to head of list
	{
		newElement->next = head;
		head = newElement;
		noEntries++;
	}
	else//there is only one entry therefore head and tail point to the same place
	{
		newElement->next = head;
		head = newElement;
		tail = newElement;
		noEntries++;
	}
}

void List::push_back(Object &newNode)
{
	Node *newElement = new Node(&newNode);

	if(head != 0)
	{
		tail->next = newElement;
		tail = newElement;
		noEntries++;
	}
	else
	{
		tail = newElement;
		head = newElement;
		noEntries++;
	}
}

//start at the head of the list
//delete items as you move along
//stop when at the end i.e. when
//the next pointer value is 0
List::~List()
{
	while(head!=0)
	{
		Node *temp = head;
		head = head->next;
		delete temp;	//delete what temp points at!
	}
}

Object &List::at(int index)
{
	Node *temp = head;
	int i;
	for(i = 0; i < index; ++i)
	{
		temp = temp->next;
	}

	return &temp->info;
}

int List::size()
{
	int i = 0;
	Node *temp = head;

	while(temp != tail)
	{
		++i;
	}
	return i;
}

void List::erase(int index)
{
	Node *temp = at(index);
	delete temp;
	//Might actually need to use the destructor at this point in which case it would be
	//something like ~Node(temp); where that deletes all variables and references relating to temp
}

//Tell each item in the list to print itself
//start at the front i.e. at the head of the list
ostream &List::print(ostream &co)
{
	Node *temp = head;			//point wherever head is pointing (head always points to current first element)
	while (temp!=0)				//while there are actually elements int the list
	{
		temp->info->printOn(co);//info is a pointer to the the first element in the list (the list itself). Call printOn for that list
		temp = temp->next; //printOn is a friend of linked list and therefore friend to all other classes used in LinkedList.h
	}
	return co; //ostream used is cout therefore return type returns a reference to an ostream in this case returning cout
}

ostream &List::printAt(ostream &co, int index)
{
	Node *temp = at(index);
	temp->info->printOn(co);

	return co;
}
#ifndef _MYLIST_H_
#define _MYLIST_H_

#include <iostream>
using namespace std;

class Object{
public:
	Object(){;}
	//Object(Object *obj);
	virtual ~Object(){;}//call destructor depending upon the derived class destructor
	virtual ostream &printOn(ostream&) const = 0;
	friend ostream &operator << (ostream &out, Object &obj)
	{
		obj.printOn(out);
		return out;
	}

};

class Node{
public:
	Node *next;
	Object *info;
	Node(Object *obj)
	{
		info = obj;
		next = 0;
	}
	~Node(){delete info;}
};

class List{
	Node *head;
	Node *tail;
	int noEntries;

public:
	List(){head = 0; tail = 0; noEntries = 0;}
	~List();
	Node *returnHead() const{return head;}
	Node *returnTail() const{return tail;}
	void add(Object &obj);
	void push_back(Object &obj);
	Object &at(int index);
	int size();
	void erase(int index);
	int isEmpty(){return head == 0;}
	ostream &print(ostream &co);
	ostream &printAt(ostream &co, int index);
};


#endif //_MYLIST_H_

I think you should do this:

CPP

Node* List::at(int index)
{
	Node *temp = head;
	int i;
	for(i = 0; i < index; ++i)
	{
		temp = temp->next;
	}

	return temp;

}
H
Node* at(int index);

Edited 7 Years Ago by programmersbook: n/a

Unfortunately that gives a similar error to the one I am currently getting

error C2440: 'initializing' : cannot convert from 'Node *' to 'Customer'

I need to somehow return an instance or pointer to customer object that is associated to its position in my list

You might want to look into Run-Time Type Identification (RTTI). I got some pretty good hits searching RTTI on Google. A good reference book is hard to beat though.

You might be able to get by with embedding the type of the object within the object so that you can use polymorphism to identify the type of the object, if all you want is to know the type.

Alternatively, you could redesign the program. Since you posted here I suspect that is your least favorite option, however.

Ok I've restructured so that I'm now using a template instead of inheriting from an object class associated with my list.

I'm almost stuck at the same point though....It is compiling and running now but when I try to print information about a customer object nothing is displayed. No errors are being thrown and I'm pretty sure the customer object is being added correctly. Can anyone explain this to me? perhaps I'm not updating the customer details correctly or my pointers aren't quite right.

Here's a test file I made to test my add functionality:

#include "Customer.h"
#include "Bank.h"

int main()
{
	int i;
	Bank theBank;

	//Customer information
			string name;
			string address;
			Date *dob;
			int dd;
			int mm;
			int yyyy;
			string telNo;
			char sex;

			cout << "Please enter customers name: " << endl;
			cin >> name;
			cout << "Please enter customers address: " << endl;
			cin >> address;
			cout << "Please enter customers telephone number: " << endl;
			cin >> telNo;
			cout << "Please enter customers date of birth: " << endl;/*Validate this section*/
			cout << "Day (dd): " << endl;
			cin >> dd;
			cout << "Month (mm): " << endl;
			cin >> mm;
			cout << "Year(yyyy): " << endl;
			cin >> yyyy;
			cout << "Please enter customers sex: " << endl;
			cin >> sex;

			dob = new Date(dd, mm, yyyy);

	Customer *c = new Customer();
	theBank.addCustomer(*c);

	theBank.displayAllCustomers();

	cin >> i;



	return 0;
}

I've added the new list files with the new template structure.
Any help would be greatly appreciated.

Edited 7 Years Ago by Valaraukar: n/a

Attachments
#include "Bank.h"

void Bank::addCustomer(Customer &newCustomer)
{
	numCustomers++;
	theCustomers.add(newCustomer);
}

void Bank::displayAllCustomers()
{
	int i;
	for (i = 0; i < theCustomers.size(); ++i)
	{
		theCustomers.at(i)->toString();//doesn't seem to print anything
	}

	cout << theCustomers.at(0)->getName() << endl;//nor does this
}
#include "myList.h"

template<class Type>
void List<Type>::add(Type &newData)
{
	Node<Type> *newNode = new Node<Type>(&newData);

	if(head != 0)
	{
		newNode->next = head;
		head = newNode;
		noEntries++;
	}
	else
	{
		newNode->next = head;
		head = newNode;
		tail = newNode;
		noEntries++;
	}
}

template<class Type>
void List<Type>::push_back(Type &newData)
{
	Node<Type> *newNode = new Node<Type>(&newData);

		if(head != 0)
		{
			tail->next = newNode;
			tail = newNode;
			noEntries++;
		}
		else
		{
			tail = newNode;
			head = newNode;
			noEntries++;
		}
}

//start at the head of the list
//delete items as you move along
//stop when at the end i.e. when
//the next pointer value is 0
/*template<class Type>
List<Type>::~List()
{
	while(head!=0)
	{
		Node<Type> *temp = head;
		head = head->next;
		delete temp;	//delete what temp points at!
	}
}*/


template<class Type>
Type *List<Type>::at(int index)
{
	Node<Type> *temp = head;
	int i;
	for(i = 0; i < index; ++i)
	{
		temp = temp->next;
	}

	return temp->dataItem;
}

template<class Type>
int List<Type>::size()
{
	int i = 0;
	Node<Type> *temp = head;

	while(temp != tail)
	{
		++i;
	}
	return i;
}

template<class Type>
void List<Type>::erase(int index)
{
	Node<Type> *temp = at(index);
	delete temp;
	//Might actually need to use the destructor at this point in which case it would be
	//something like ~Node(temp); where that deletes all variables and references relating to temp
}
#ifndef _MYLIST_H_
#define _MYLIST_H_

#include <iostream>
using namespace std;

template<class Type>		//Forward decleration of the List class
class List;

template<class Type>
class Node{
public:
	Type *dataItem;
	Node *next;
	Node(Type *nodeData)
	{
		dataItem = nodeData;
		next = 0;
	}
	~Node<Type>(){delete info;}
	friend class List<Type>;
};

template<class Type>
class List{
	Node<Type> *head;
	Node<Type> *tail;
	int noEntries;

public:
	List<Type>(){head = 0; tail = 0; noEntries = 0;}
	//~List<Type>(){;}//doesn't seem to like this yet....
	Node<Type> *returnHead() const{return head;}
	Node<Type> *returnTail() const{return tail;}
	void add(Type &nodeData);
	void push_back(Type &nodeData);
	Type *at(int index);
	int size();
	void erase(int index);
	int isEmpty(){return head == 0;}
	//ostreams go here
};

#endif //_MYLIST_H_

You seem to capture the customer details correctly from the user but when you create a new Customer()

Customer *c = new Customer();
theBank.addCustomer(*c);

how are you passing the customer details to the customer object i.e customer name, address, date of birth etc...?

Customer *c = new Customer(name, address, dob, etc.....);
theBank.addCustomer(*c);

Definition of template member funtions needs to be in the header file, not in the cpp file.

Where is Bank.h? From what is posted I can only guess at what's in Bank.

I hope Bank.h includes the STL string header file and the files necessary for the Customer and Date classes. Otherwise to need to include them as well.

Here's how I would restructure the Node class

template<class Type>
class Node
{
   public:
     Type dataItem;
     Node * next;
     Node(Type nodeData)
     {
         dataItem = nodeData;
         next = 0;
     }
     ~Node<Type>(){}
};

Ok I restructured my Nodes as suggested but it made no difference other than I have to use a . and not a -> when accessing the customer functionality.
I didn't have the STL string header but even after I included it it made no difference.
I just can't see why it wouldn't be printing anything but not throwing an error and continuing to run as if it had printed.

I've attached the bank header now aswell :)

Attachments
#ifndef _BANK_H_
#define _BANK_H_

#include "Customer.h"
//#include "Account.h"
//#include "Mortgage.h"
#include "myList.h"
#include "myList.cpp"

using namespace std;

class Bank{
	int numCustomers;

	List<Customer> theCustomers;

public:
	//General functions
	void displayAllCustomers();

	//Manipulation of Customers
	void addCustomer(Customer &c);
};
#endif

@caged_fire;

After You capture the customer details from the user, how are you passing the variables: name, address, dob, telNo and sex to the new customer?

Consider, after you capture the customer details you then create a customer c = new customer(); yes?
The customer class should have defined in it variables name, address, dob, telNo and sex. E.g:

class Customer
{
String name, address, telNo, sex;
Date dob;
public:
Customer(String &n, string &a, string &t, string &s, Date &d): name(n), address(a), telNo(t), sex(s), dob(d){}

///then you various methods proceed........
};

Then after capturing the customer details from the user in the main method you then pass them to the new customer through the constructor to read something like

Customer *c = new Customer(name, address, dob, telNo, sex)

then when you call c->getname it should show you the name

This question has already been answered. Start a new discussion instead.