I want to independently overload operator+ to concatenate 2 double chained lists. My idea is to obtain the address of the first element from the first list and the address of the first element from the second list.
In DoubleChainedList class, except the constructor, destructor and the next 4 methods which are working fine, I made a method called get_prim which is supposed to get me the address of the first element from the specified list. Then, using the method get_current I want to move through the first list until it ends while adding in the third list the elements, and then apply the same principle to the second list.
But I have a problem, I get
'get_prim' was not declared in this scope
and
'get_current' was not declared in this scope
at the bolded tagged lines (see the code below) when I compile. What am I missing?
#include <iostream>
#include <stdlib.h>
using namespace std;
//Create node class
class Node
{
private:
float value;
Node *back;
Node *next;
public:
Node *set_value (Node *x, float element) { x->value=element; return x; }
float get_value (Node *x) { return x->value; }
Node *set_back (Node *x) { return x->back; }
Node *set_next (Node *x) { return x->next; }
Node *set_back_nod (Node *x, Node *y) { x->back=y; return x; }
Node *set_next_nod (Node *x, Node *y) { x->next=y; return x; }
void next_to_2next (Node *x) { x->next=x->next->next; }
void next_back_to_origins (Node *x) { x->next->back=x; }
};
//Create list class
class DoubleChainedList : public Node
{
private:
Node *prim;
Node *ultim;
public:
DoubleChainedList() { prim=NULL; ultim=prim; } //Constructor
~DoubleChainedList(); //Destructor
void insert_back(float element); //Inserts an element at the end of the list
void delete_element_from_position(int delete_position); //Deletes from the list the element whose position is equal to "delete_position"
void show_left_right(); //Shows the list from the first element to the last one
void show_right_left(); //Shows the list from the last element to the first one
Nod *get_prim (DoubleChainedList myList) { return this->prim; }; //Intended to obtain the address of the first element from "myList"
Nod *get_current (Node *x) { return set_next(x); }; //Intended to move me through the list
};
DoubleChainedList operator+ (DoubleChainedList myList1, DoubleChainedList myList2)
{
DoubleChainedList myList3;
Nod *current1,*current2;
current1=get_prim(myList1); // ERROR OVER HERE!
current2=get_prim(myList2);
cout<<get_value(current1)<<" "; // ERROR OVER HERE!
cout<<get_value(current2)<<" ";
return myList3;
}
int main()
{
int i,number_elem_myList1,number_elem_myList2,element;
DoubleChainedList myList1,myList2,myList3;
cin>>number_elem_myList1;
for (i=0;i<number_elem_myList1;i++)
{
cin>>element;
myList1.insert_back(element);
}
cin>>number_elem_myList2;
for (i=0;i<number_elem_myList2;i++)
{
cin>>element;
myList2.insert_back(element);
}
myList3=myList1+myList2;
return 0;
}
If you implement operator+= as a member function, you can have access to the other list's variables.
I would implement operator+=, then traverse the other list, appending the other list's nodes to this list.
And pass the other list as const &.
Functions called with e.g. someObject.function(...) or someObject->function(...) (where someObject is respectively either an object or a pointer to an object of some class that has a function(...) function) have direct access to the members of someObject.
So functions that are members of a class doesn't need to be passed an object of that class as parameter, unless you want to work with 2 objects in that function.
The functions of Node should probably look more like:
void set_value (float element) { value = element; }
float get_value () { return value; }
Node *set_back () { return back; }
Node *set_next () { return next; }
void set_back_nod (Node *y) { back = y; }
void set_next_nod (Node *y) { next = y; }
void next_to_2next () { next = next->next; }
void next_back_to_origins () { next->back = this; }
Also, get_prim:
Node *get_prim() { return prim; };
Which then leads to a operator+ which looks more like: (const & as Thomas suggested)
DoubleChainedList operator+ (const DoubleChainedList &myList1,
const DoubleChainedList &myList2)
{
DoubleChainedList myList3;
Node *current1, *current2;
current1 = myList1.get_prim();
current2 = myList2.get_prim();
cout << current1->get_value() << " ";
cout << current2->get_value() << " ";
// ...
return myList3;
}
Using operator+= as Thomas suggested is probably also a better idea.
Modified the program as follows, but I still have a problem. If I try to display the list outside the procedure "operator+", I get "Segmentation fault" (when I debugged the program it happened immediately after this instruction: "myList3=myList1+myList2;"). If I display it inside that procedure, everything's OK. I think that this is happening because of that "return" statement and because I return a temporary object which will no longer exists after the "operator+" procedure ends, but I don't know how to fix that.
#include <iostream>
using namespace std;
//Create node class
class Node
{
private:
float value;
Node *back;
Node *next;
public:
Node *set_value (float element) { value=element; return this; }
float get_value () { return value; }
Node *set_back () { return back; }
Node *set_next () { return next; }
Nod *set_back_node (Node *y) { back=y; return this; }
Nod *set_next_node (Node *y) { next=y; return this; }
void next_to_2next () { next=next->next; }
void next_back_to_origins () { next->back=this; }
};
//Create list class
class DoubleChainedList : public Node
{
private:
Node *prim;
Node *ultim;
public:
DoubleChainedList() { prim=NULL; ultim=prim; } //Constructor
~DoubleChainedList(); //Destructor
void insert_back(float element); //Inserts an element at the end of the list
void delete_element_from_position(int delete_position); //Deletes from the list the element whose position is equal to "delete_position"
void show_left_right(); //Shows the list from the first element to the last one
void show_right_left(); //Shows the list from the last element to the first one
Node *get_prim () { return prim; } //Intended to obtain the address of the first element from a list
};
DoubleChainedList operator+ (DoubleChainedList myList1, DoubleChainedList myList2)
{
DoubleChainedList myList3;
Node *current1,*current2,*current3;
current1=myList1.get_prim();
current2=myList2.get_prim();
while ((current1!=NULL)||(current2!=NULL))
{
if (current1!=NULL)
{
myList3.insert_back(current1->get_value());
current1=current1->set_next();
}
else
if (current2!=NULL)
{
myList3.insert_back(current2->get_value());
current2=current2->set_next();
}
}
//myList3.show_left_right();
//cout<<endl;
//myList3.show_right_left();
return myList3;
}
int main()
{
int i,number_elem_myList1,number_elem_myList2,element;
DoubleChainedList myList1,myList2,myList3;
cin>>nr_elem_lista1;
for (i=0;i<number_elem_myList1;i++)
{
cin>>element;
myList1.insert_back(element);
}
cin>>number_elem_myList2;
for (i=0;i<number_elem_myList2;i++)
{
cin>>element;
myList2.insert_back(element);
}
myList3=myList1+myList2;
myList3.show_left_right();
myList3.show_right_left();
return 0;
}
#Dukeling modified the methods of the "Node" class as you said (and of course the program where necessary) and it's OK, too.
I can post the full code if is someone interested, but it has more than 200 lines, the name of variables/dates, procedures/methods and also some comments wrote in Romanian (my natural language) and it would be harder for someone new to understand it.
Related
This question already has answers here:
What is object slicing?
(18 answers)
Closed 8 years ago.
I have two classes, Object and Ball. Ball is derived from Object. Object has a virtual function "move" and a non virtual function "moveFast" that calls move. Class Ball redefines the move function from it's parent class.
#include <iostream>
struct Object
{
virtual void move(int dist)
{
std::cout<<"Moving "<<dist<<std::endl;
}
void moveFast(int multiplier)
{
move(10*multiplier);
}
};
struct Ball : public Object
{
void move(int dist)
{
std::cout<<"Rolling "<<dist<<std::endl;
}
};
class List
{
struct Node
{
Node* next;
Object ele;
Node(Object e, Node* n=NULL) : ele(e), next(n){}
};
Node* head;
public:
List() : head(NULL){}
void addObj(Object o)
{
if(head==NULL)
{
head = new Node(o);
return;
}
Node* current = head;
while(current->next!=NULL)
{
current=current->next;
}
Node* obj = new Node(o);
current->next=obj;
}
void doStuff()
{
Node* current = head;
while(current!= NULL)
{
current->ele.moveFast(10);
current=current->next;
}
}
};
int main()
{
Object a,b,c;
Ball d;
List list;
list.addObj(a);
list.addObj(b);
list.addObj(c);
list.addObj(d);
list.doStuff();
}
The List class takes in Objects and calls their moveFast function. Because a,b, and c are just Objects I would expect the first 3 lines of output to be "Moving 100".
d however, is an instance of the Ball class. So I would expect the 4th line of output to say "Rolling 100", because Ball redefined the move function.
Right now all the output prints
Moving 100
Moving 100
Moving 100
Moving 100
Is there a way to get Ball's definition of move called from List?
The problem is that you store your Objects in the list by value. virtual functions will only work on pointers. the moment you try to add an object to the list through list::void addObj(Object o). The argument is passed by value. This means that it is copied and if you copy a base class only the base class functionality will be copied it's called the slicing problem (like dyp mentioned). you should change your nodes to hold a pointer to the object and redo your add object function to take a pointer to the element to prevent copying and slicing.
like this
class List
{
struct Node
{
Node* next;
Object* ele;
Node(Object* e, Node* n=nullptr) : ele(e), next(n){}
};
Node* head;
public:
List() : head(nullptr){}
void addObj(Object* o)
{
if(head==nullptr)
{
head = new Node(o);
return;
}
Node* current = head;
while(current->next!=nullptr)
{
current=current->next;
}
Node* obj = new Node(o);
current->next=obj;
}
void doStuff()
{
Node* current = head;
while(current!= nullptr)
{
current->ele->moveFast(10);
current=current->next;
}
}
};
int main()
{
Object a,b,c;
Ball d;
List list;
list.addObj(&a);
list.addObj(&b);
list.addObj(&c);
list.addObj(&d);
list.doStuff();
return 0;
}
which outputs:
Moving 100
Moving 100
Moving 100
Rolling 100
Like many have said, there was a slicing problem in List.
List::Node stored an actual Object, so when an instance of Ball was passed into addObj(Object o), the additional functionality of Ball was "sliced", and only the parts stored by it's base class "Object" remained.
Changing the Node class to store an Object pointer instead of an Object instance fixed this problem. This change also requires the addObj function to be altered to take in a pointer. The List class now looks like this:
class List
{
struct Node
{
Node* next;
Object* ele;//<-- This is the Big change
Node(Object* e, Node* n=NULL) : ele(e), next(n){}
};
Node* head;
public:
List() : head(NULL){}
void addObj(Object* o)
{
if(head==NULL)
{
head = new Node(o);
return;
}
Node* current = head;
while(current->next!=NULL)
{
current=current->next;
}
Node* obj = new Node(o);
current->next=obj;
}
void doStuff()
{
Node* current = head;
while(current!= NULL)
{
current->ele->moveFast(10);
current=current->next;
}
}
};
changing int main() to provide the altered inputs results in the expected output.
int main()
{
Object *a,*b,*c;
b=c=a=new Object();
Ball* d = new Ball();
List list;
list.addObj(a);
list.addObj(b);
list.addObj(c);
list.addObj(d);
list.doStuff();
}
Here's the reversePrint function:
void SinglyLinkedList::reversePrint(Node* p)
{
if (p == NULL) {
return;
} else {
reversePrint(p->next);
cout << p->data << " ";
}
}
(i.e: list = 1 -> 2 -> 3 -> 4, print out = 4 3 2 1 )
It will only work if *p initially points to what *head points to, namely the first node 1. However, Node* head is a private member of SinglyLinkedList class thus can't be accessed outside the class. How can I pass a pointer that points to head from main ?
Here's what I'm talking about:
int main() {
SinglyLinkedList *list = new SinglyLinkedList();
list->addNode(1);
list->addNode(2);
list->addNode(3);
list->addNode(4);
Node* p = head; // <---- Xcode says: Use of undeclared identifier 'head'
list->reversePrint(p);
return 0;
}
I tried to point *p to what *head points to from inside the reversePrint method. But, it disrupted the recursion
class SinglyLinkedList {
public:
// constructor
SinglyLinkedList();
// destructor
~SinglyLinkedList();
// public APIs
void print();
void addNode(int number);
void reversePrint(Node* p);
private:
Node* head;
};
Move the member function that works with a Node* to the private section.
Create a public member function that does not take any input. Implement it using the private member function.
void SinglyLinkedList::reversePrint()
{
this->reversePrint(this->head);
}
Call the public member function without the Node* in calling function.
list->reversePrint();
You can define one public method without parameters and another private method with a parameter that is called from the public method. For example
public:
void reversePrint() const { reversePrint( head ); }
private:
void reversePrint(Node* p) const { /*...*/ }
Make void SinglyLinkedList::reversePrint(const Node* p) const private,
and add a public overload void SinglyLinkedList::reversePrint() const which calls reversePrint(head).
Alternatively, you may add getter to head.
I have a misunderstanding here. I'm designing a Queue class which uses the Client class as the base unit. The list structure consists of a pointer to the next data and a variable for holding the Client object.
The Queue class has 2 ways of operating. The way of it's operating is determined by the bool MODE variable. If mode equals 1, then the Queue class uses placement new operator, and if not, it uses the new operator.
This is the Queue class's prototype:
class Queue
{
private:
const int max_lists;
int no_lists, counter;
char client_value;
list *chunk;
list *top;
const bool MODE;
void addFirst(const Client &c);
void addLast(const Client &c);
void deleteLast();
void deleteFirst();
void clean_mem();
void clean_mem(list *&pos);
list* malloc();//T* type
public:
Queue();
Queue(list *buffer,int no);
Queue(const Queue &q);
Queue& operator=(const Queue &q);
~Queue() { clean_mem(); }
void enqueue(const Client &c);
void timeoutCustomers();
void decreaseTimeout();
Client getCustomer() const;
void finishCustomer();
void show() const;
};
The functions definitions which contribute to the error given are here:
void Queue::addFirst(const Client &c)
{
if(top==nullptr)
{
top = malloc();
top->info = c;
top->next = nullptr;
}
else
{
list *add = malloc();
add->info = c;
add->next = top;
top = add;
}
}
list* Queue::malloc()
{
if(MODE)
{
if(no_lists==max_lists)
{
return nullptr;
}
else
{
list *tmp = chunk;
counter = 0;
while(counter++<max_lists)
{
client_value = (char)tmp->info;
if(client_value==-1 && tmp->next==nullptr)
{
return new(tmp) list;
}
tmp++;
}
return nullptr;
}
}
else
{
return new list;
}
}
And here's the list structure:
struct list { Client info; list *next; };
When I make an instance of the Queue class, I can choose whether I go on placement new or just the new operator.
If I choose the placement new, I'm have to send the address of an array of type list. The address is saved into chunk pointer. The top pointer holds the first address of the linked list.
Then, if I call the addFirst() function it stops at top->info = c. The error points to top->info :
CXX0030: Error: Expression cannot be evaluated.
But when I switch back to new operator, everything works. This tells me that there's a problem with the allocation of a new portion in the already allocated memory.
Can somebody give me a direction of what's the problem here?
Did you intend your malloc function like that? You have an 'else' block AFTER your functions definition and not all control paths return a value. I have a rewrite here that seems to match more with what I think you actually intend:
list* Queue::malloc()
{
if(MODE)
{
if(no_lists==max_lists)
{
return nullptr;
}
else
{
list *tmp = chunk;
counter = 0;
while(counter++<max_lists)
{
client_value = (char)tmp->info;
if(client_value==-1 && tmp->next==nullptr)
{
return new(tmp) list;
}
tmp++;
}
return nullptr;
}
}
else
{
return new list;
}
}
I'm trying to create a doubly-linked list with the null object model. So far, I've implemented a method to add a node to the beginning of the list and a method to display the node. My problem is that the display function always displays 0. Can anyone point out where I've gone wrong and how to fix it? Also, am I on the right track to correctly implementing the null object model here?
Note: This is a school assignment. Please don't just post a solution without an explanation. I want to learn and understand what's going on here.
Edit: After fixing the display problem, I have another: When calling getHead() or getTail() with a list that is empty or has nodes, it keeps wanting to use self() from the node class, rather than the nullNode class (in the event of an empty list) or elementNode class (in the event of a list with nodes). I'm stuck on how to fix this.
If I print out the addresses of container.getNext() and container (for an empty list), both addresses are the same so shouldn't adding ->self() to the end call the self() method from the nullNode class?
class node {
public:
node(){/* Do nothing */}
node(int e){ element = e; }
int getData(){ return element; }
void setData(int e){ element = e; }
friend class list;
protected:
node* getNext(){ return next; }
void setNext(node* n){ next = n; }
node* getPrev() { return prev; }
void setPrev(node* n){ prev = n; }
node* self();
private:
int element;
node* next;
node* prev;
};
class nullNode : public node{
public:
nullNode(){/* Do nothing */}
int getData(){ return NULL; }
void setData(int e){ /* Do Nothing */ }
node* getNext(){ return head; }
void setNext(node* n){ head = n; }
node* getPrev() { return tail; }
void setPrev(node* n){ tail = n; }
node* self(){ return NULL; }
private:
node* head;
node* tail;
};
class elementNode : public node{
public:
elementNode(){/* Do nothing */}
elementNode(int element){
setData(element);
}
int getData(){ return node::getData(); }
void setData(int e){ node::setData(e); }
node* getNext(){ return node::getNext(); }
void setNext(node* n){ node::setNext(n); }
node* getPrev() { return node::getPrev(); }
void setPrev(node* n){ node::setPrev(n); }
node* self(){ return this; }
};
class list{
public:
list();
node* getHead(){ return (container.getNext())->self(); }
node* getTail(){ return (container.getPrev())->self(); }
node* addHeadNode(int e);
void removeNode(node* n);
void insertBefore(node* n, int e);
void insertAfter(node* n, int e);
void displayNode(node *n);
private:
nullNode container;
};
list::list()
{
container.setNext(&container);
container.setPrev(&container);
}
node* list::addHeadNode(int e)
{
node* foo = new elementNode(e);
foo->setPrev(&container);
foo->setNext(container.getNext());
container.getNext()->setPrev(foo);
container.setNext(foo);
return foo;
}
void list::displayNode(node* n)
{
cout << "Node Data: " << n->getData() << endl;
}
int main()
{
list myList;
node* myNode;
myNode = myList.addHeadNode(5);
myList.displayNode(myNode);
return 0;
}
elementNode(int element)
{
node e;
e.setData(element);
}
What is this code doing? You create node e, but it appears to then be thrown away and not added to any list.
The problem hides in
elementNode(int element){
node e;
e.setData(element);
}
What is going on here? First you create an instance of the node class and then call its setData member function. Sure enough e is modified with the value of element but the very next moment both e and element are vanished out of existence because the scope where they were initialized has ceased to its end (terminated by }) while the information in element hasn't been saved anywhere.
However, if you replace the above code with
elementNode(int element){
setData(element);
}
it calls the inherited setData member function, the value of element is saved, and the program outputs 5 as expected.
Your elementNode constructor is trying to initialize it's node part:
elementNode(int element){
node e;
e.setData(element);
}
You actually just construct an unrelated node then discard it.
What you want is to call your superclass constructor, which can be done in the subclass constructor's initialization list:
elementNode(int element) : node(element) {
}
$ I have the following error:
44 E:\Assignment 2.cpp no match for 'operator<<' in 'std::cout < (&number)->newstack::push(x)'
$ I'm using a linked list to put numbers in a class stack that contains a struct. The stack that contains these numbers are printed out. But the error will not allow me to print them out.
#include <iostream>
using namespace std;
typedef int itemType;
class newstack
{
private:
Using a struct of nodes which contains a item and pointer to the next node.
struct node
{
itemType item;
node *next;
};
node *top; //pointer to the top node.
public:
void push(itemType newItem); //adds items to newstack
};
int main()
{
newstack number;
int x;
cout<< "Number Stack" <<endl;
for (x=0;x<=9;x++)
cout<<(number).push(x)<<endl; //ERROR LINE
//Takes 9 integers and adds them to the stack by printing them out.
return 0;
}
void newstack::push(itemType newItem)
// Precondition: Stack is empty.
//Postcondition: Stack contains a itemType at the top and list or stack implements by 1.
{
if(top!=NULL)
node *newTop;
newTop=new node;
(*newTop).item=newItem;
(*newTop).next=top;
top=newTop;
}
IN your push() function you are returning Void.
Yet you try and write the value the function returns
to the command prompt - either change your push function
to return a value or cout << stack.pop();
Further On:
You need to overload the << operator for your newstack class to be able to write something like:
newstack obj;
cout<<obj;
<< is overloaded for only built-in data types not custom class types.
You need to overload it something like this:
std::ostream& operator<<(std::ostream& os, const newstack& obj);
cout<<(number).push(x)<<endl;
First, you don't need the () around number
cout << number.push(x) << endl;
That still won't work, because newstack::push returns void.
Either change newstack::push to return the value added, or print the number in a separate step.
See The Following
#include <iostream>
using namespace std;
//Defenitions
template <class T>
struct Node
{
T DataMember;
Node* Next;
};
template <class T>
class NCA
{
public:
NCA();
~NCA();
void push(T);
T pop();
void print();
void Clear();
private:
Node<T>* Head;
void* operator new(unsigned int);
};
//Imp.
template <class T>
NCA<T>::NCA()
{
Head = NULL;
}
template <class T>
NCA<T>::~NCA()
{
Clear();
}
template <class T>
void NCA<T>::push(T value)
{
Node<T>* Temp = new Node<T>;
Temp->DataMember = value;
Temp->Next = Head;
Head = Temp;
}
template <class T>
T NCA<T>::pop()
{
Node<T>* n;
T i;
n = Head->Next;
i = Head->DataMember;
delete Head;
Head = n;
return i;
}
template <class T>
void NCA<T>::print()
{
Node<T>* MockHead = Head;
while (MockHead != NULL)
{
cout << MockHead->DataMember;
MockHead = MockHead->Next;
}
}
template <class T>
void NCA<T>::Clear()
{
while(Head != NULL)
pop();
}
//Main Execution
int main()
{
NCA<char> Array;
Array.push('c');
cout << Array.pop();
return 0;
}
You haven't override the operator << for your newstack which is causing the error. If you printed x, then did the push afterwards, you wouldn't receive an error. If you want cout to be able to print your stack you need to define HOW the << operator works.
The real problem here is how you're expecting your code to work. First, push shouldn't return a value to begin with, that's not how a stack works. You could implement pop which would pop off and return the top value of the stack, however then you're losing that value. You need to implement peek. Because this is homework I wont give you a direct answer on how to write peek but this should be a better way of executing your code.
for (x=0; x<=9; x++)
{
number.push(x);
cout << number.peek() << endl;
}