c++ virtual functions with Linked List - c++

I'm running into some problems while trying to use a virtual function within my classes.
I'm using a Linked List to store Employee, Staff and Managers - which inherit each other (Staff and Managers inherit Employee base class).
I need to be able to access a function called getType which returns either "Staff Member" or "Manager" based on which class it is.
this snipit of code is my creation of staff and managers.
Staff staff4 = { "Lisa", "22/02/2012", 0004, HR, 8.9, 34.50 };
Employee* pStaff4 = &staff4;
Employee& testStaff4 = staff4;
myList->addInFront(testStaff4);
Staff staff5 = { "Jade", "23/03/2014", 0003, HR, 6.4, 38.50 };
Employee* pStaff5 = &staff5;
Employee& testStaff5 = staff5;
myList->addInFront(testStaff5);
Manager manager1 = { "Lily", "01/09/2012", 0001, MARKETING, 75968 };
Employee* pMan1 = &manager1;
Employee& testMan1 = manager1;
myList->addInFront(testMan1);
Manager manager2 = { "Craig", "27/03/2011", 0002, HR, 82478 };
Employee* pMan2 = &manager2;
Employee& testMan2 = manager2;
myList->addInFront(testMan2);
//cout << pStaff5->getType();
//system("pause");
This is my employee.h (i've taken out other functions to save space on this post)
class Employee
{
protected:
string name;
string startDate;
unsigned long empNumber;
string dept;
public:
Employee() {};
Employee(string, string, unsigned long, string);
virtual const string getType()
{
return "Emp";
}
};
class Manager : public Employee
{
private:
unsigned long salary;
public:
virtual const string getType()
{
return "Manager";
}
};
class Staff : public Employee
{
private:
float hourlyRate;
float hoursPerWeek;
public:
const string getType()
{
return "Staff Member";
}
};
and finally this is how i'm attempting to call the getType() function:
void displayList(const List& list)
{
List temp(list);
while (!temp.isEmpty())
{
cout << temp.first()->item.getType() << "\n";
cout << temp.first()->item.getName() << "\n";
temp.deleteFirst();
}
}
Here is my list header and .cpp
list.h
//#include <string>
#include "Employees.h"
#define Item Employee
using namespace std;
struct Node
{
Item item;
Node* next;
};
class List
{
private:
Node* head;
Node* end() const;
void copy(const List&);
void destroy();
public:
List();
List(const List&);
~List();
List& operator=(const List&);
bool operator==(const List&);
bool isEmpty() const;
Node* first() ;
Item last() const;
List tail() const;
void addInFront(const Item&);
void addAtEnd(const Item&);
void deleteFirst();
Node* search(const long);
bool searchDelete(const long);
};
list.cpp
#include "stdafx.h"
#include "List.h"
#include <assert.h>
List::List()
{
head = NULL;
}
List::List(const List& otherList) : head(nullptr)
{
copy(otherList);
}
bool List::isEmpty() const
{
return (head == nullptr);
}
Node* List::first()
{
assert(head != nullptr);
return head;
}
void List::deleteFirst()
{
if (head != NULL)
{
Node* tmp = head->next;
delete head;
head = tmp;
}
}
void List::addInFront(const Item& data)
{
Node* nodePtr = new Node;
assert(nodePtr != nullptr);
nodePtr -> item = data;
nodePtr ->next = head;
head = nodePtr;
}
Node* List::search(const long longID)
{
}
bool List::searchDelete(const long longID)
{
Node *temp, *prevNode;
temp = head;
prevNode = NULL;
while (temp != NULL)
{
}
}
Node* List::end() const
{
if (head == nullptr)
return nullptr;
else
{
Node* nodePtr = head;
while (nodePtr->next != nullptr)
{
nodePtr = nodePtr->next;
}
return nodePtr;
}
}
void List::addAtEnd(const Item& data)
{
Node* nodePtr = new Node;
assert(nodePtr != nullptr);
if (head == nullptr)
{
head = nodePtr;
nodePtr->item = data;
}
else
{
nodePtr->item = data;
Node* ptr = end();
ptr->next = nodePtr;
}
}
List& List::operator=(const List& rhs)
{
if (&rhs != this)
{
destroy();
copy(rhs);
}
return *this;
}
void List::copy(const List& otherList)
{
}
void List::destroy()
{
while (head != nullptr)
{
Node* ptr = head;
head = head->next;
delete ptr;
}
}
List::~List()
{
}
apologies about the length of these files.
I'm confused as to why it won't call the appropriate virtual function, as you can see in the first code snipit that i used pStaff5->getType() and that worked - however I can't access the nodes like that once i've stored them in a linked list...(can I?)
Kind regards
Craig

Your list nodes store an Item but that is only the base class. When you try to put a Manager or Staff in the list only the base class part of the object is copied into the list (this is called "slicing") and not the derived parts of the object.
When you call the virtual function you only get the base class overrider for the virtual, because the object stored in the list is only an Employee.
(You should consider making Node and List into templates, instead of doing #define Item Employee)

Related

a simple payroll system using linked list c++

i am simply creating a payroll system that has a employee name and a working hours for that employee.. the data is supposed to be stored in a linked list data structure, but i can not connect the linked list to the object of the class employee, i tried making the pay roll linked list (i.e empList) as a static member so that all the objects of the class can use the same list object and data can be stored but once i compile my code i get an error of "undefined reference to employee::empList" at line 130 that is the last line of constructor, same error on line 150 that is a print pay roll function.. where ever i am trying to call any payRollLinkedList class's function in employee class it gives error.. bottom line is that all i want is to data be stored in a doubly linked list of employees and i can not access the list.
#include <iostream>
using namespace std;
class payRollLinkedList;
class node
{
private:
node* previousPointer;
string name;
int hoursWorked;
node* nextPointer;
friend class payRollLinkedList;
public:
explicit node(const string argName, const int argHoursWorked)
: previousPointer{nullptr}, name{argName}, hoursWorked{argHoursWorked}, nextPointer{nullptr}
{}
};
class payRollLinkedList
{
private:
node* headPointer{nullptr};
node* tailPointer{nullptr};
node* getNewNode(const string argName, const int argHoursWorked)
{
return new node(argName, argHoursWorked);
}
public:
void addAtBack(const string argName, const int argHoursWorked)
{
node* newNode{getNewNode(argName, argHoursWorked)};
if(isEmpty())
{
headPointer = tailPointer = *newNode;
}
else
{
tailPointer->nextPointer = newNode;
newNode->previousPointer = tailPointer;
tailPointer = newNode;
newNode = nullptr;
delete newNode;
}
}
bool deleteNode(string argName)
{
node* currentPointer{headPointer};
if(isEmpty())
{
cout <<"the list is already empty\n";
return false;
}
else
{
while(currentPointer != nullptr)
{
if(currentPointer->name == argName)
{
if(currentPointer == headPointer)
{
node* tempPointer{headPointer};
headPointer = headPointer->nextPointer;
tempPointer->nextPointer = nullptr;
headPointer->previousPointer = nullptr;
delete tempPointer;
break;
}
if(currentPointer == tailPointer)
{
node*tempPointer{tailPointer};
tailPointer = tailPointer->previousPointer;
tempPointer->previousPointer = nullptr;
tailPointer->nextPointer = nullptr;
delete tempPointer;
break;
}
node* tempPointer{currentPointer};
node* nextPtr{tempPointer->nextPointer};
currentPointer = currentPointer->previousPointer;
currentPointer->nextPointer = nextPtr;
nextPtr->previousPointer = currentPointer;
tempPointer->nextPointer = nullptr;
tempPointer->previousPointer = nullptr;
currentPointer = nullptr;
nextPtr = nullptr;
delete tempPointer;
delete currentPointer;
delete nextPtr;
}
else
currentPointer = currentPointer->nextPointer;
}
return true;
}
}
void print()
{
if(isEmpty())
{
cout <<"nothing to show\n";
return;
}
else
{
node* currentPointer{headPointer};
while(currentPointer != nullptr)
{
cout <<currentPointer->name <<"\t";
currentPointer = currentPointer->nextPointer;
}
}
}
bool isEmpty()
{
return headPointer == nullptr? true : false;
}
};
class employee
{
private:
string name;
int hoursWorked;
static payRollLinkedList empList;
public:
employee()
: name{""}, hoursWorked{0}
{}
employee(string argName, int argHoursWorked)
{
name = argName;
hoursWorked = argHoursWorked;
empList.addAtBack(name, hoursWorked);
}
void printPayRoll()
{
empList.print();
}
};
int main()
{
employee emp("usman", 12);
employee emp1("ali", 12);
emp.printPayRoll();
}
https://en.cppreference.com/w/cpp/language/static
You need to define static member of class at global scope (out of class).
i suggest you to split your code .h and .cpp files and define the member in .cpp file.
payRollLinkedList employee::empList;

How to declare friend classes while using decorator and iterator design patterns

I have created a ListAsDLL class (doubly linked list) by decorating a ListAsSLL class (singly linked list). Now I would like to incorporate an Iterator class to cycle through the ListAsDLL class. My code is as follows:
#include <iostream>
using namespace std;
class ListAsSLL
{
protected:
struct node{
int i;
struct node* next;
};
node* head;
node* tail;
int listSize;
public:
ListAsSLL()
{
head = 0;
tail = 0;
listSize = 0;
}
virtual void addToBeginning(int i)
{
node * temp = new node;
temp->i = i;
if(head==0){
temp->next = 0;
tail = temp;
}else if(head == tail) {
temp->next = tail;
}
else{
temp->next = head;
}
head = temp;
listSize++;
}
virtual void print()
{
node* temp = head;
for (int i = 0; i < listSize; ++i) {
cout<<temp->i<<" "<<endl;
temp = temp->next;
}
}
};
class Decorator : public ListAsSLL
{
private:
ListAsSLL* list;
public:
Decorator(ListAsSLL* l)
{
list = l;
}
virtual void addToBeginning(int i)
{
list->addToBeginning(i);
}
virtual void print()
{
list->print();
}
};
class PreviousDecorator : public Decorator
{
protected:
struct dnode : public node
{
node* prev;
};
dnode* head;
dnode* tail;
int listSize;
public:
PreviousDecorator(ListAsSLL* l) : Decorator(l)
{
listSize = 0;
head = 0;
tail = 0;
}
virtual void addToBeginning(int i)
{
Decorator::addToBeginning(i);
dnode * temp = new dnode;
temp->i = i;
if(head==0){
temp->next = 0;
tail = temp;
}else if(head == tail) {
temp->next = tail;
tail->prev = temp;
}
else{
temp->next = head;
tail->prev = temp;
}
temp->prev = 0;
head = temp;
listSize++;
}
virtual void print()
{
Decorator::print();
node* temp = head;
for (int i = 0; i < listSize; ++i) {
cout<<temp->i<<" "<<endl;
temp = temp->next;
}
}
friend class DLLIterator;
};
class ListAsDLL : public ListAsSLL
{
public:
virtual void addToBeginning(int i){}
virtual void print(){}
};
class DLLIterator
{
private:
ListAsDLL* dll;
public:
DLLIterator(ListAsDLL* dll)
{
this->dll = dll;
}
int getFirst()
{
return dll->head->i;
}
};
int main() {
ListAsSLL* dll = new PreviousDecorator(new ListAsDLL());
dll->addToBeginning(20);
DLLIterator* it = new DLLIterator((ListAsDLL*) dll);
cout<<it->getFirst()<<endl;
delete dll;
delete it;
return 0;
}
The only problem is that because I am passing in a ListAsDLL as a parameter to the Iterator class I am unable to access the protected attributes of the class it is being decorated with. Therefore I cannot access dll->head->i.
Firstly, am I using the decorator design pattern correctly? And secondly how can I access the protected attributes of a class that a friend class has been decorated with.
Your class hierarchy is:
ListAsSSL (a first head) <- Decorator <- PreviousDecorator (another head)
^
|---- ListAsDLL
You cannot cast a PreviousDecorator into a ListAsDLL even if they have a base class in common. Moreover, in the PreviousDecorator::addToBeginning method you write PreviousDecorator::head and not ListAsSSL::head that remains nullptr.
As you want to custom the cells, a solution could be just to let the type of the node open at the level of the class ListAsSLL with a virtual method like createEmptyNode. The ListAsDLL can override this method to create a double linked node as in the code below.
#include <iostream>
using namespace std;
class ListAsSLL
{
protected:
struct node{
int i;
struct node* next;
};
node* head;
node* tail;
int listSize;
public:
ListAsSLL()
{
head = 0;
tail = 0;
listSize = 0;
}
virtual node* createEmptyNode() const { return new node{}; }
virtual node* addToBeginning(int i)
{
node * temp = createEmptyNode();
temp->i = i;
if(head==0){
temp->next = 0;
tail = temp;
}else if(head == tail) {
temp->next = tail;
}
else{
temp->next = head;
}
head = temp;
listSize++;
return temp;
}
virtual void print()
{
node* temp = head;
for (int i = 0; i < listSize; ++i) {
cout<<temp->i<<" "<<endl;
temp = temp->next;
}
}
};
class ListAsDLL : public ListAsSLL
{
protected:
struct dnode : public node
{
dnode* prev;
};
virtual node* createEmptyNode() const { return new dnode{}; }
public:
virtual node* addToBeginning(int i)
{ node* result = ListAsSLL::addToBeginning(i);
static_cast<dnode*>(tail)->next = static_cast<dnode*>(result);
static_cast<dnode*>(result)->prev = static_cast<dnode*>(tail);
}
virtual void print(){}
friend class DLLIterator;
};
class DLLIterator
{
private:
ListAsDLL* dll;
public:
DLLIterator(ListAsDLL* dll)
{
this->dll = dll;
}
int getFirst()
{
return dll->head->i;
}
};
int main() {
ListAsSLL* dll = new ListAsDLL();
dll->addToBeginning(20);
DLLIterator* it = new DLLIterator((ListAsDLL*) dll);
cout<<it->getFirst()<<endl;
delete dll;
delete it;
return 0;
}
The following code uses the decorator pattern with a new hierarchy level to avoid data duplication. ListAsSLL represents the implementation that can manage single linked cells and double linked cells.
The new class hierarchy is:
List <- ListAsSSL (implementation = head, tail)
^
|- Decorator (SLL) <- PreviousDecorator (DLL)
I have kept the original names for the classes but you can modify them.
#include <iostream>
#include <cassert>
#include <memory>
using namespace std;
class List {
public:
virtual ~List() {}
virtual void addToBeginning(int i) {}
virtual void print() const {}
virtual int getFirst() const { assert(false); }
};
class PreviousDecorator;
class ListAsSLL : public List
{
protected:
struct node{
int i;
struct node* next;
node(int val) : i(val), next(nullptr) {}
};
node* head;
node* tail;
int listSize;
friend class PreviousDecorator;
public:
ListAsSLL()
{
head = 0;
tail = 0;
listSize = 0;
}
virtual ~ListAsSLL()
{ node* cell = head;
for (int i=0; i<listSize; ++i) {
node* temp = cell->next;
delete cell;
cell = temp;
}
}
void addToBeginning(node* anode)
{
node * temp = anode;
if(head==0){
temp->next = 0;
tail = temp;
}else if(head == tail) {
temp->next = tail;
}
else{
temp->next = head;
}
head = temp;
listSize++;
}
virtual void addToBeginning(int i) { addToBeginning(new node(i)); }
virtual void print() const
{
node* temp = head;
for (int i = 0; i < listSize; ++i) {
cout<<temp->i<<" "<<endl;
temp = temp->next;
}
}
virtual int getFirst() const { assert(head); return head->i; }
};
class Decorator : public List
{
private:
std::unique_ptr<ListAsSLL> list;
protected:
ListAsSLL& getImplementation() { return *list; }
public:
Decorator(ListAsSLL* l) : list(l) {}
virtual void addToBeginning(int i)
{
list->addToBeginning(i);
}
virtual void print() const
{
list->print();
}
virtual int getFirst() const { return list->getFirst(); }
};
class DLLIterator;
class PreviousDecorator : public Decorator
{
protected:
struct dnode : public ListAsSLL::node
{
node* prev;
dnode(int val) : node(val), prev(nullptr) {}
};
public:
PreviousDecorator(ListAsSLL* l) : Decorator(l) {}
virtual void addToBeginning(int i)
{ dnode* anode = new dnode(i);
getImplementation().addToBeginning(anode);
anode->prev = static_cast<dnode*>(getImplementation().tail);
getImplementation().tail->next = anode;
}
friend class DLLIterator;
};
class DLLIterator
{
private:
PreviousDecorator* dll;
public:
DLLIterator(PreviousDecorator* dll)
{
this->dll = dll;
}
int getFirst() const
{
return dll->getFirst();
}
};
int main() {
PreviousDecorator* dll = new PreviousDecorator(new ListAsSLL());
dll->addToBeginning(20);
cout<<dll->getFirst()<<endl;
delete dll;
return 0;
}

C++ Variable Scope Issues

I'm trying to implement a singly linked list in c++ and I'm running into a lot of scope issues and I'm not sure why. I'm getting errors like LinkedList.cpp:28:11: error: ‘class LinkedList’ has no member named ‘current’ if(this->current == NULL)
Here's my .h file
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
class Node
{
friend class LinkedList;
private:
int data;
Node* next;
Node* getNext() { return this->next; };
public:
Node() { data = 0; next = NULL; };
void setData(int data) { this->data = data; };
void setNext(Node* next) { this->next = next; };
};
class LinkedList
{
private:
Node* head;
Node* current;
public:
LinkedList() { head = current = NULL; };
//LinkedList(const LinkedList &l)
//TO DO: Destructor
void next();
void reset();
void append(int data);
void replaceData(int data);
void removeNode(int data);
void removeLast();
bool reset();
void operator++() { next(); };
};
#endif
and here is my cpp file (There my be more issues, especially with the implementation of the LinkedList, but I'm more concerned with the current compilation errors)
#include "LinkedList.h"
#include <stddef.h>
void LinkedList::next()
{
if(current != NULL)
{
current = current->next;
}
}
void LinkedList::reset()
{
if(head != NULL)
{
current = head;
}
}
void LinkedList::append(int data)
{
Node* newNode = new Node();
newNode->setData(data);
newNode->setNext(NULL);
reset();
if(this->current == NULL)
{
this->head = newNode;
}
else
{
while(this->current->getNext() != NULL)
{
this->current = this->current->getNext();
}
this->current->setNext(newNode);
}
}
void LinkedList::removeNode(int data)
{
this->current = this->head;
if(this->current == NULL) return;
if(this->current->getNext() == NULL)
{
delete this->current;
this->head = NULL;
}
else
{
Node* previous;
do
{
if(this->current->getData() == data) break;
previous = this->current;
this->current = this->current->getNext();
} while(this->current != NULL);
previous->setNext(this->current->getNext());
delete this->current;
}
}
void LinkedList::removeLast()
{
this->current = this->head;
while(this->current->getNext() != NULL)
{
this->current = this->current->getNext();
}
delete this->current;
}
I realize I'm more than likely missing something so incredibly obvious, but I cannot figure this out to save my life.
void reset();
bool reset();
function cannot be overloaded by return type.
void LinkedList::removeNode(int data)
{
if (this->current->getData() == data) break;
}
Your node class doesn't have a getData() function.
I've successfully compiled your code by fixing those 2 issues Live Demo.
If that isn't enough, then perhaps you are probably not including the LinkedList header at all.

Binary Search Tree Template

I'm fairly new to c++ and I've recently received a project to create my own Binary Search Tree using a Template. The goal is for the Binary Tree to be able to take in any kind of data type. IntBinaryTree.h should be able to take in object of EmployeeInfo. I've gotten it to compile but I get an error message of glibc detected double free or corruption (fasttop) I'm not exactly sure what this means. Also I'm not sure if I've set the program up correctly. Also note, I'm testing functions 1 by 1 in main.cpp that's why there is only insert function being used.
Update I allocated memory for the insertNode function by TreeNode *newNode = new TreeNode, now I get error message of "in instantiation of void IntBinaryTree::insertNode(T) [with T = EmployeeInfo]: main.cpp:22:29 required from here "
#ifndef EMPLOYEEINFO_H
#define EMPLOYEEINFO_H
#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
class EmployeeInfo
{
public:
EmployeeInfo(int, string);
~EmployeeInfo();
//void print();
int getEmployeeID();
string getEmployeeName();
void setEmployeeID(int);
void setEmployeeName(string);
bool operator ==(const EmployeeInfo &eO1) {return EmployeeID == eO1.EmployeeID;}
bool operator >(const EmployeeInfo &eO1) {return EmployeeID > eO1.EmployeeID;}
bool operator <(const EmployeeInfo &eO1) {return EmployeeID < eO1.EmployeeID;}
private:
int EmployeeID;
string EmployeeName;
};
#endif
#include"EmployeeInfo.h"
#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
EmployeeInfo::EmployeeInfo(int empID, string name)
{
EmployeeID = empID;
EmployeeName = name;
}
EmployeeInfo::~EmployeeInfo()
{
}
int EmployeeInfo::getEmployeeID()
{
return EmployeeID;
}
string EmployeeInfo::getEmployeeName()
{
return EmployeeName;
}
void EmployeeInfo::setEmployeeID(int empID)
{
EmployeeID = empID;
}
void EmployeeInfo::setEmployeeName(string name)
{
EmployeeName = name;
}
#ifndef INTBINARYTREE_H
#define INTBINARYTREE_H
#include <iostream>
#include<string>
#include<cstdlib>
#include <iomanip>
using namespace std;
template<class T>
struct TreeNode
{
T value;
TreeNode<T> *left;
TreeNode<T> *right;
};
template<class T>
class IntBinaryTree
{
private:
TreeNode<T>* root;
void insert(TreeNode<T> *&, TreeNode<T> *&);
void destroySubTree(TreeNode<T> *);
void deleteNode(T, TreeNode<T> *&);
void makeDeletion(TreeNode<T> *&);
void displayInOrder(TreeNode<T> *) const;
void displayPreOrder(TreeNode<T> *) const;
void displayPostOrder(TreeNode<T> *) const;
public:
//Constructor
IntBinaryTree();
~IntBinaryTree(){destroySubTree(root);}
//Binary Tree Operations
void insertNode(T);
bool searchNode(T);
void remove(T);
void displayInOrder() const{ displayInOrder(root);}
void displayPreOrder() const{ displayPreOrder(root);}
void displayPostOrder() const{ displayPostOrder(root);}
};
template<class T>
IntBinaryTree<T>::IntBinaryTree()
{
root = NULL;
}
template<class T>
void IntBinaryTree<T>::insert(TreeNode<T> *&nodePtr, TreeNode<T> *&newNode)
{
if (nodePtr == NULL)
nodePtr = newNode;
else if (newNode->value < nodePtr->value)
insert(nodePtr->left, newNode);
else
insert(nodePtr->right, newNode);
}
template<class T>
void IntBinaryTree<T>::insertNode(T val)
{
TreeNode<T> *newNode;
newNode->value = val;
newNode->left = newNode->right = NULL;
//Insert the Node
insert(root, newNode);
}
template<class T>
void IntBinaryTree<T>::displayInOrder(TreeNode<T> *nodePtr) const
{
if(nodePtr){
displayInOrder(nodePtr->left);
cout << nodePtr->value << " ";
displayInOrder(nodePtr->right);
}
}
template<class T>
void IntBinaryTree<T>::displayPreOrder(TreeNode<T> *nodePtr) const
{
if(nodePtr){
cout << nodePtr->value << " ";
displayPreOrder(nodePtr->left);
displayPreOrder(nodePtr->right);
}
}
template<class T>
void IntBinaryTree<T>::displayPostOrder(TreeNode<T> *nodePtr) const{
if(nodePtr){
displayPostOrder(nodePtr->left);
displayPostOrder(nodePtr->right);
cout << nodePtr->value << " ";
}
}
template<class T>
void IntBinaryTree<T>::destroySubTree(TreeNode<T> *nodePtr){
if(nodePtr != NULL)
{
if(nodePtr->left != NULL)
{
destroySubTree(nodePtr->left);
}
if(nodePtr->right != NULL)
{
destroySubTree(nodePtr->right);
}
delete nodePtr;
}
cout << "Binary Tree Destroyed\n";
}
template<class T>
bool IntBinaryTree<T>::searchNode(T val){
TreeNode<T>* nodePtr = root;
while(nodePtr){
if (nodePtr->value == val)
return true;
else if (val < nodePtr->value)
nodePtr = nodePtr->left;
else
nodePtr = nodePtr->right;
}
return false;
}
template<class T>
void IntBinaryTree<T>::remove(T val){
deleteNode(val, root);
}
template<class T>
void IntBinaryTree<T>::deleteNode(T val, TreeNode<T> *&nodePtr){
if (val < nodePtr->value)
deleteNode(val, nodePtr->left);
else if (val > nodePtr->value)
deleteNode(val, nodePtr->right);
else
makeDeletion(nodePtr);
}
template<class T>
void IntBinaryTree<T>::makeDeletion(TreeNode<T> *&nodePtr){
TreeNode<T> *tempNodePtr;
if (nodePtr == NULL)
cout << "Cannot delete empty node\n";
else if(nodePtr->right == NULL)
{
tempNodePtr = nodePtr;
nodePtr = nodePtr->left;
delete tempNodePtr;
}
else if(nodePtr->left == NULL)
{
tempNodePtr = nodePtr;
nodePtr = nodePtr->right;
delete tempNodePtr;
}
//If the node has two Children
else
{
//Move one node to the right
tempNodePtr = nodePtr->right;
//Go to the end left node
while(tempNodePtr->left)
tempNodePtr = tempNodePtr->left;
//Reattach the left subtree
tempNodePtr->left = nodePtr->left;
tempNodePtr = nodePtr;
//Reattach the right subtree
nodePtr = nodePtr->right;
delete tempNodePtr;
}
}
#endif
#include"EmployeeInfo.cpp"
#include"IntBinaryTree.h"
#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
int main()
{
IntBinaryTree<EmployeeInfo> mytree;
EmployeeInfo employee1(1021, "John Williams");
EmployeeInfo employee2(1057, "Bill Witherspoon");
EmployeeInfo employee3(2487, "Jennifer Twain");
EmployeeInfo employee4(3769, "Sophia Lancaster");
EmployeeInfo employee5(1017, "Debbie Reece");
EmployeeInfo employee6(1275, "George McMullen");
EmployeeInfo employee7(1899, "Ashley Smith");
EmployeeInfo employee8(4218, "Josh Plemmons");
mytree.insertNode(employee1);
mytree.insertNode(employee2);
mytree.insertNode(employee3);
mytree.insertNode(employee4);
mytree.insertNode(employee5);
mytree.insertNode(employee6);
mytree.insertNode(employee7);
mytree.insertNode(employee8);
return 0;
}
In your insertNode method, you do not allocate any space for your node and you use an uninitialized pointer:
TreeNode<T> *newNode;
newNode->value = val;
newNode->left = newNode->right = NULL;
You need to allocate some memory for your node:
TreeNode<T> *newNode = new TreeNode<T>;
I highly recommend learning to use the debugger, so you can trace through your code line by line to see what it is doing. No one writes perfect code each time, and a debugger is the easiest way to see what is going wrong.
Edit:
The above won't work as you don't have a default constructor for Employee, but you only have a default constructor for TreeNode. This means you can't create a TreeNode that contains an Employee.
The best way to fix this, is to add a constructor to TreeNode that takes a parameter that is a reference to a T object, so that it can initialize its own value object from that parameter.
Add this to your TreeNode class
TreeNode(T &val) : value(val), left(NULL), right(NULL) { }
This code copies the val parameter into value and initializes the left and right pointers.
Then change your insert code to.
TreeNode<T> *newNode = new TreeNode < T > (val) ;
//Insert the Node
insert(root, newNode);
Note that there is no need to set the left and right pointers, as the constructor now does that for you.

C++ custom template LinkedList crashes adding std::string

For academic purposes, I'm trying to develop a little "textual adventure game". I have to implement all data structures by my own. Now, I have some problems with the implementation of a generic (template) LinkedList.
In the specific, this data structure works with everything (primitive data types and custom objects) BUT strings! (standard library strings).
When I try to add strings to a list, the application crashes with the following error (in console):
"terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_constructor null not valid"
The list is implemented as a "double linked list" using the head-node as first-last node
Here the code ("Abstract" List interface):
#ifndef LIST_H_
#define LIST_H_
template <class T>
class List
{
public:
virtual ~List() {}
virtual T get(int position) = 0;
virtual List* add(T item) = 0;
virtual List* insert(T item, int position) = 0;
virtual List* remove(int position) = 0;
virtual int size() const = 0;
virtual bool isEmpty() const = 0;
protected:
private:
};
#endif /* LIST_H_ */
This is the LinkedList implementation (the "node" class):
#include "List.h"
#include <stdlib.h>
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
template <class T>
class ListNode
{
public:
ListNode(T item)
{
mItem = item;
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item;
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem;
}
T getItem()
{
return mItem;
}
ListNode<T>* getNext()
{
return mNext;
}
ListNode<T>* getPrev()
{
return mPrev;
}
void setItem(T item)
{
mItem = item;
}
void setNext(ListNode<T>* next)
{
mNext = next;
}
void setPrev(ListNode<T>* prev)
{
mPrev = prev;
}
protected:
private:
T mItem;
ListNode<T> *mNext, *mPrev;
};
The LinkedList class:
template <class K>
class LinkedList : public List<K>
{
public:
LinkedList()
{
mSize = 0;
mFirstNode = NULL;
}
~LinkedList()
{
// implementazione distruttore tramite ciclo sui nodi
}
K get(int position)
{
K item = NULL;
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL) item = targetNode->getItem();
return item;
}
List<K>* add(K item)
{
if (mFirstNode == NULL)
{
mFirstNode = new ListNode<K>(item);
mFirstNode->setNext(mFirstNode);
mFirstNode->setPrev(mFirstNode);
}
else
{
ListNode<K>* newNode = new ListNode<K>(item, mFirstNode, mFirstNode->getPrev());
mFirstNode->getPrev()->setNext(newNode);
mFirstNode->setPrev(newNode);
}
mSize++;
return this;
}
List<K>* insert(K item, int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
ListNode<K>* newNode = new ListNode<K>(targetNode->getItem(), targetNode->getNext(), targetNode);
targetNode->setItem(item);
targetNode->setNext(newNode);
mSize++;
}
return this;
}
List<K>* remove(int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
targetNode->setItem(targetNode->getNext()->getItem());
targetNode->setNext(targetNode->getNext()->getNext());
//delete targetNode->getNext();
mSize--;
}
return this;
}
int size() const
{
return mSize;
}
bool isEmpty() const
{
return (mFirstNode == NULL) ? true : false;
}
protected:
ListNode<K>* getNodeAtPosition(int position)
{
ListNode<K>* current = NULL;
if (mFirstNode != NULL && position < mSize)
{
current = mFirstNode;
for (int i = 0; i < position; i++)
{
current = current->getNext();
}
}
return current;
}
private:
int mSize;
ListNode<K>* mFirstNode;
};
#endif /* LINKEDLIST_H_ */
Suggestions?
Part of your problem is here:
ListNode(T item)
{
mItem = item; // for a std::string, this will be a class member, non-pointer
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item; // same here
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem; // you are attempting to delete an item you never created
}
You should either change your constructors to create a T* object on the heap (which will then be deleted in your destructor), or remove the delete line from your destructor.
This problem will be evident with far more than just std::string, by the way.
Somewhere in your program you are doing this:
std::string s(nullptr);
Calling std::string's constructor with a null pointer is causing it to throw a std::logic_error exception.
From the standard:
§ 21.4.2
basic_string(const charT* s, size_type n, const Allocator& a = Allocator());
Requires: s shall not be a null pointer and n < npos.
It seems it's not possible to pass std::string as template argument...
Strings as Template Arguments
Now I use an "old" - char const* - to achieve the expected result, even if I have to implement my personal "utils" methods to work with those pointers now...