Linked list containig different derived class objects in c++ - c++

How we can create a linked list which can contain a different class of object. for example, if a person is base class and it has student and teacher as a derived class so How I can create a linked list which can contain both classes of objects like student also and teacher also.
below I wrote the source code for that but it is not working.
#include<iostream>
#include<string>
using namespace std;
int classNum;
class person
{
public:
string name;
public:
person(string="");
void show_p_name();
};
class student:public person
{
public:
string s_name;
int rollnum;
public:
student(string="", string="", int=100);
void show_name();
};
class worker:public person
{
public:
string w_name;
int work_id;
public:
worker(string="", string="", int=200);
void show_name();
};
// person
person::person(string nm)
{
name = nm;
}
void person::show_p_name()
{
cout << "In person class name is: " << name << endl;
}
// student inheriate person
student::student(string nm, string snm, int rolln)
:person(nm)
{
s_name = snm;
rollnum = rolln;
}
void student::show_name()
{
cout << "In student class name is: " << s_name << endl;
}
// worker inheriate person
worker::worker(string nm, string wnm, int wid)
:person(nm)
{
w_name = wnm;
work_id = wid;
}
void worker::show_name()
{
cout << "In worker class name is: " << w_name << endl;
}
// structure declaration
struct Node
{
person *p;
struct Node *next;
};
struct Node* createNode()
{
struct Node *t;
t = new struct Node;
classNum++;
if(t == NULL)
{
cout << "Memory Not Allocated\n";
//exit(0);
}
else
{
return t;
}
}
void initLink(struct Node *n)
{
n->next = NULL; //Make next as NULL
}
void initNode(struct Node *temp)
{
if((classNum % 2) == 0)
{
/*
temp->p = new student;
static_cast<student*>(temp->p)->name = "person_s_sahil";
static_cast<student*>(temp->p)->s_name = "student_sahil";
static_cast<student*>(temp->p)->rollnum = 100;
temp->p = static_cast<student*>(temp->p);
*/
temp->p = new student();
temp->p->name = "person_s_sahil";
temp->p->s_name = "student_sahil";
temp->p->rollnum = 100;
}
else
{
/*
temp->p = new worker;
static_cast<worker*>(temp->p)->name = "person_w_sahil";
static_cast<worker*>(temp->p)->w_name = "worker_sahil";
static_cast<worker*>(temp->p)->work_id = 100;
temp->p = static_cast<worker*>(temp->p);
*/
temp->p = new worker()
temp->p->name = "person_w_sahil";
temp->p->w_name = "worker_sahil";
temp->p->work_id = 100;
}
}
void attachEnd(struct Node **hptr, struct Node *tn)
{
struct Node *cn;
if(*hptr == NULL) //if list is empty
{
*hptr = tn; //attach new node to head
}
else
{
cn = *hptr; //get first node call as currunt node
while(cn->next != NULL) //get last node
{
cn = cn->next;
}
cn->next = tn; //attach new node to next of last node
}
}
void traverse(struct Node *hptr)
{
struct Node *temp;
if(hptr == NULL)
{
cout << "List is empty\n";
}
else
{
temp = hptr;
while(temp != NULL)
{
temp->p->show_name();
temp = temp -> next;
}
}
}
main()
{
struct Node *head = NULL;
struct Node *temp;
temp = createNode();
initLink(temp);
initNode(temp);
attachEnd(&head, temp);
traverse(head);
// like that I want to create node and attach to linked list
}

Proper approach would be to create linked list of pointers to objects of type Person.
Then you will populate it with pointers to instances of classes Student and Teacher. You have to create it dynamically (new keyword)
And now magic comes with using of keyword virtual for method declaration in Person class. Check this in google c++ polymorphism and C++ virtual method
If you latter call virtual method on pointer to Person object it will call proper method from derived class.
Do not forget to call delete for each element in list at the end of usage (program). And for this you have to define virtual destructor in Person class
In your case you should define Person class like this
class person
{
public:
string name;
virtual ~person() {};
public:
person(string="");
virtual void show_name();
};
Or another approach could be to use dynamic_cast<>() but for this you need to enable it in compiler. It is called RTTI (runtime type information). With dynamic cast you can safely cast from Person to Student or Teacher. If dynamic cast is not able to do cast it will return nullptr. So you can check this value.

Slightly fixed code (for purpose of compile-ability):
void initNode(struct Node *temp)
{
if ((classNum % 2) == 0)
{
/*
temp->p = new student;
static_cast<student*>(temp->p)->name = "person_s_sahil";
static_cast<student*>(temp->p)->s_name = "student_sahil";
static_cast<student*>(temp->p)->rollnum = 100;
temp->p = static_cast<student*>(temp->p);
*/
auto s = new student();
temp->p = s;
temp->p->name = "person_s_sahil";
s->s_name = "student_sahil";
s->rollnum = 100;
}
else
{
/*
temp->p = new worker;
static_cast<worker*>(temp->p)->name = "person_w_sahil";
static_cast<worker*>(temp->p)->w_name = "worker_sahil";
static_cast<worker*>(temp->p)->work_id = 100;
temp->p = static_cast<worker*>(temp->p);
*/
auto p = new worker();
temp->p = p;
temp->p->name = "person_w_sahil";
p->w_name = "worker_sahil";
p->work_id = 100;
}
void traverse(struct Node *hptr)
{
struct Node *temp;
if (hptr == NULL)
{
cout << "List is empty\n";
}
else
{
temp = hptr;
while (temp != NULL)
{
temp->p->show_p_name();
temp = temp->next;
}
}
}
If you fix your code, it will work (at a glance).

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;

Creating objects with new in function and "this is nullptr" exception

I've been trying to make a template class (called List) which stores different type of objects. I created Base class to be like base in my program and Human class. Base can create new Human and to have access to them all, has a (private) pointer to List * first_h (in every List is stored Human* me, List * next and List * first_h (first_h in list)).
The problem is, when I add like more than 1 Human to my Base, I can't display them properly. I think it's because of creating new Human's in Base method (void Base::create_human(string name)) but everything I did don't work it out.
There are my classes:
class Human
{
private:
string name;
public:
Human(string name) { this->name = name; }
void display() { cout << "My name: " << name << endl; }
};
template <class T>
class List
{
private:
T* me;
List <T>* next;
List <T>* first;
public:
void set_me(T* me) { this->me = me; }
T* get_me() { return this->me; }
void set_next(List* next) { this->next = next; }
List <T>* get_next() { return this->next; }
void set_first(List* first) { this->first = first; }
List <T>* get_first() { return this->first; }
void add(T*& created);
void display();
};
class Base
{
private:
List <Human>* first_h;
public:
void set_first_h(List <Human>*& first) { this->first_h = first; }
List <Human>* get_first_h() { return this->first_h; }
void create_human(string name)
{
Human* created = new Human(name);
this->first_h->add(created);
}
};
and methods:
template <class T>
void List<T>::add(T*& created)
{
List <T>* temp = this->get_first();
List <T>* new_list;
if ((this->get_me()) == nullptr)
{
this->set_next(nullptr);
this->set_me(created);
this->set_first(this);
}
else
{
new_list = new List <T>;
temp = this->get_first();
while (temp != nullptr)
{
temp = temp->get_next();
}
new_list->set_next(nullptr);
new_list->set_first(this->get_first());
temp->set_next(new_list);
}
}
template <class T>
void List<T>::display()
{
List <T>* temp_list = this;
T* temp;
if (temp_list == nullptr)
{
std::cout << "There is nothing!" << endl;
}
while (temp_list != nullptr)
{
temp = temp_list->get_me();
temp->display();
temp_list = temp_list->get_next();
}
std::cout << "End!" << endl;
}
and my main function:
int main()
{
Base Main;
List <Human>* first_h = new List <Human>();
Main.set_first_h(first_h);
Main.create_human("Jane");
Main.create_human("John");
Main.create_human("Mary");
Main.get_first_h()->display();
system("pause");
return 0;
}
Sorry for my English and thank you in advance!
Edit:
I found out what was wrong:
in add function:
new_list->set_next(nullptr);
new_list->set_me(created);
new_list->set_first(this->get_first());
temp->set_next(new_list);
I forgot about:
new_list->set_me(created);
the mistake in add function as one of you wrote.
Your loop
while (temp != nullptr)
{
temp = temp->get_next();
}
runs till temp is nullptr and then you do
temp->set_next(new_list);
So, as you see, inside set_next() the this pointer is nullptr.
Please learn how to use a debugger and look at the call stack.

Making list of objects of class with function overloading

I am having a class Car, now I want to make linked list of Car objects. So for this I am having a Node class to hold data for each node.
class StringOfCar;
class Node
{
private:
Node* next;
Car* data;
Node ()
{
next = 0;
data = 0;
}
public:
friend class StringOfCar;
};
And StringOfCar
class StringOfCar
{
private:
Node* head;
Node* tail;
public:
StringOfCar(){
head=0;
tail=0;
}
void output();
void push (Car &);
};
Now I push the elements without any problem with this function :
void StringOfCar::push(Car & new_car)
{
Car *currentCarPtr;
Node *currentNodePtr;
currentNodePtr = new Node;
currentCarPtr = new Car(new_car);
currentNodePtr->next = 0;
currentNodePtr->data = &new_car;
if (head == 0)
{
head = currentNodePtr;
tail = currentNodePtr;
}
else
{
tail->next = currentNodePtr;
tail = currentNodePtr;
}
}
But when I try to output, program stops abruptly.I have output() for Car class also. Output function for both class is as follow :
void StringOfCar::output(){
Node * currentNodePtr = head;
if (head == 0)
cout << "NO cars \n";
else
{
while (currentNodePtr != 0)
{
currentNodePtr->data->output();
currentNodePtr = (currentNodePtr->next);
}
}
}
And for Car class :
void Car::output()
{
cout<<"\nreportingMark "<<setw(3)<<reportingMark;
cout<<"\ncarNumber "<< setw(8)<< carNumber;
cout<<"\nkind " << setw(13)<<KIND_ARRAY[kind];
if (loaded==true)
{
cout<<" \nloaded true";
}
else if (loaded == false)
{
cout<< "\nloaded false";
}
cout<< "\ndestination "<<setw(7)<<destination<<endl;
}
When I comment currentNodePtr->data->output(); this line, it works fine. What can be problem ? Please help
I think the problem is in this line:
currentNodePtr->data = &new_car;
of the function void StringOfCar::push(Car & new_car).
That should be
currentNodePtr->data = currentCarPtr;

C++ Changing Struct to Class [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am doing linked list exercises and currently understand how to write a link list in struct format. However I would like to change my code to make linked list a class and have the print, sort, add, delete, functions as members of the class. Please give me ideas on how this can be done.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstddef>
using namespace std;
struct mylist {
int payload;
struct mylist * link;
};
void addlink(struct mylist *, int);
struct mylist * droplink(struct mylist *);
void printmylist(struct mylist *);
void sortmylist(struct mylist *);
int main() {
struct mylist head;
struct mylist *lptr;
head.payload = 15;
head.link = 0;
lptr = &head;
printmylist(lptr);
addlink(lptr, 21);
printmylist(lptr);
addlink(lptr, -5);
printmylist(lptr);
addlink(lptr, 90);
printmylist(lptr);
lptr = droplink(lptr);
printmylist(lptr);
sortmylist(lptr);
printmylist(lptr);
return 0;
}
void addlink(struct mylist *lp, int val) {
struct mylist *temp;
struct mylist *newlink;
//run out to end of chain
temp = lp;
do {
if (temp->link != 0)
temp = temp->link;
} while (temp->link != 0);
newlink = (struct mylist *) malloc(sizeof(struct mylist));
newlink->payload = val;
newlink->link = 0;
temp->link = newlink;
return;
}
struct mylist * droplink(struct mylist *lp) {
cout << "Releasing front value of " << lp->payload << endl;
return lp->link;
}
void printmylist(struct mylist *lp) {
struct mylist *temp;
temp = lp;
while (temp->link != 0) {
cout << temp->payload << " then ";//if there is just one link, loop never runs
if (temp->link != 0)
temp = temp->link;
}
cout << temp->payload; //gets the last link's value
cout << endl;
return;
}
void sortmylist(struct mylist *lp) {
struct mylist *temp;
struct mylist *temp2;
int linkcount = 1;
int temppayload;
temp = lp;
while (temp->link != 0) {
if (temp->link != 0) {
++linkcount;
temp = temp->link;
}
}
cout << linkcount << " links " << endl;
temp = lp;
for (int ct2 = 1; ct2 < linkcount; ++ct2) {
temp = lp;
for (int ct = 1; ct < linkcount; ++ct) {
if (temp->link != 0)
temp2 = temp->link;
if (temp->payload > temp2->payload) {
temppayload = temp->payload;
temp->payload = temp2->payload;
temp2->payload = temppayload;
}
if (temp2->link != 0)
temp = temp2;
}
}
}
The only real difference between a struct and a class in C++ is that by default all members of a class are private, and all members of a struct are public.
I assume what you're really asking is how to make your linked list methods members of your struct / class. This is very easy.
All of your existing methods accept a struct mylist* as the first parameter. In C++, this is provided automatically by the compiler, as a hidden parameter called this. You can refer to this explicitly, but it is also accessible implicitly.
So where in C you might have:
lp->payload = 0;
In a C++ class member function, you could have:
this->payload = 0;
Or more commonly:
payload = 0;
So broadly speaking, the steps required to "c++ify" your C code are:
Move the declarations of the methods into the body of the struct
Remove the struct mylist * argument from each method
Remove the references to lp in each method
Call the member functions by dereferencing an instance of the struct (e.g. lptr->addlink(-5);)
As a rule, you can change every struct that is passed to a linked list function from:
struct Node {
int payload;
struct Node *link;
};
...
void addlink(struct Node *lp, int val) {
...
}
to this:
class Node {
public:
Node() : _link(0), _payload(0) { } // initialize members on new empty node
Node(int val) : _link(0), _payload(val) { } // pass a new value directly
~Node() {
// call a function to clear everything pointed to from _link
}
void addlink(int val) {
Node *temp = this;
do {
if (temp->link() != 0)
temp = temp->link();
} while (temp->link() != 0);
Node *newlink = new Node(val); // this will do what the next 2 lines do
//Node *newlink = new Node; <- you can also create a Node this way and then assign the payload
//newlink->setPayload(val);
// newlink->link = 0; <-- not needed 'new Node' has already initialized it
temp->setLink(newlink);
}
// provide access to the data (get/set)
int payload() { return _payload; }
void setPayload(int n) { _payload = n; }
Node *link() { return _link; }
void setLink(Node *p) { _link = p; }
// data members
private:
int _payload;
Node *_link;
};
This fragment gives you the idea. Now you can add the rest :)
The best of course, is to place the code within the functions in a .cpp file and leave the definition of the class in the header:
class Node {
public:
Node();
Node(int val); // pass a new value directly
~Node();
void addlink(int val);
// provide access to the data (get/set)
// you can leave thse one liners in the header, they'll most likely be inlined
int payload() { return _payload; }
void setPayload(int n) { _payload = n; }
Node *link() { return _link; }
void setLink(Node *p) { _link = p; }
// data members
private:
int _payload;
Node *_link;
};
The bodies of the functions in the cpp:
Node::Node() : _link(0), _payload(0)
{
}
Node::Node(int val) : _link(0), _payload(val)
{
}
......
Hope this helps.

Trying to add to a LinkedList in C++. Getting a SegFault

So I am trying to add to a Linked List in c++ and I keep getting a SegFault for some reason.
Stock is the class that will 'be' the LinkedList and StockAccount is the class that will be accessing it.
The way I am inserting data into is is that it goes through a file line buy line and parses the information on the current line and inserts it into the list.
This is my code that I am using to add to the list:
void StockAccount::addStock(string sN, double sP) {
Stock *temp, *temp2;
temp->StockName = sN;
temp->StockPrice = sP;
temp->next = NULL;
if (myHead == NULL) {
myHead = temp;
} else {
temp2 = myHead;
while (temp2->next != NULL) {
temp2 = temp2->next;
}
temp2->next = temp;
}
}
The SegFault seems to be happening at the line where I define
temp->StockName=sN;
I am new to c++ so my guess is that I am using pointers/references wrong.
Here is how I define the Stock class:
#include <string>
using namespace std;
using std::string;
class Stock {
friend class StockAccount;
public:
Stock() {
}
Stock(string name, double price) : StockName(name), StockPrice(price) {
this->next = NULL;
}
private:
string StockName = "";
double StockPrice = 0;
Stock *next;
};
and here is how I define the StockAccount class. Account is just a simple base class.
class StockAccount : public Account {
friend class Account;
public:
StockAccount();
void addStock(string sN, double sP);
private:
Stock *myHead;
Stock *myTail;
};
And the implementation of it:
StockAccount::StockAccount() {
vector<string> temp;
string line;
std::ifstream stockfile("Results.txt");
if (stockfile.is_open()) {
while (stockfile.good()) {
getline(stockfile, line);
istringstream ss(line);
string token;
while (std::getline(ss, token, ',')) {
temp.push_back(token);
}
//*stck = new stock(token.at(0), atof(temp.at(1)));
addStock(temp.at(0), atof(std::string(temp.at(1)).c_str()));
temp.clear();
}
stockfile.close();
} else {
cout << "Unable to open file" << std::endl << std::endl;
}
}
//http://www.codeproject.com/Articles/24684/How-to-create-Linked-list-using-C-C
void StockAccount::addStock(string sN, double sP) {
Stock *temp, *temp2;
temp->StockName = sN;
temp->StockPrice = sP;
temp->next = NULL;
if (myHead == NULL) {
myHead = temp;
} else {
temp2 = myHead;
while (temp2->next != NULL) {
temp2 = temp2->next;
}
temp2->next = temp;
}
}
The variable temp is uninitialized. By doing temp->StockName = sN;, you are essentially trying to dereference an invalid pointer, which of course gives you a segmentation fault.
What you need to do is allocate a stock object by doing Stock *temp = new Stock(); before you attempt to do anything with it.