Virtual function call from inside a base class function [duplicate] - c++

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();
}

Related

Class member function works normally, but gets stuck in an infinite loop when called as a data member of another class

I wrote a tree structure and made a basic search function to look for nodes within the tree. The tree itself uses a sentinel node to mark all ends (parent of the root, child of the leaves), and search simply iterates through nodes until it either finds a match or hits the sentinel node. The search function works fine when I call it on an instance of a tree, however it gets stuck when the tree is a data member of another class. In the following code, "t.search(1)" works, but "embedded_tree.t.search(1)" gets stuck in an infinite loop.
I have narrowed it down to the fact that when the call to embedded_tree.t.search() is made, the content of "&sentinel" correctly points to the sentinel node, but seems to be a new pointer, as it is not equivalent to the contents of root, sentinel.parent, and sentinel.child. From here I am stuck and am not sure how to call it so that &sentinel matches the pointers that were created when the tree was constructed.
#include <iostream>
struct NODE {
int key;
NODE* parent;
NODE* child;
NODE() : key(0), parent(NULL), child(NULL) {};
};
struct TREE {
NODE sentinel;
NODE* root;
TREE()
{
sentinel = *new NODE;
sentinel.parent = &sentinel;
sentinel.child = &sentinel;
root = &sentinel;
}
NODE* search(int k)
{
NODE* x = root;
while (x != &sentinel)
{
if (x->key == k) return x;
x = x->child;
}
return &sentinel;
}
};
struct A {
TREE t;
A() : t(*new TREE()) {};
};
int main()
{
TREE t;
t.search(1);
A embedded_tree;
embedded_tree.t.search(1);
}
You're confusing dynamic memory allocation with stack allocation. When you do
sentinel = *new NODE
bad things happen. Memory gets allocated for NODE sentinel on the stack, then for NODE in new operator, then assignment gets done to sentinel variable, and memory created in new operator is lost. You should rewrite your code to use pointers instead, and add destructors, something like this
#include <iostream>
struct NODE {
int key;
NODE* parent;
NODE* child;
NODE() : key(0), parent(NULL), child(NULL) {};
};
struct TREE {
NODE* sentinel;
NODE* root;
TREE()
{
sentinel = new NODE;
sentinel->parent = sentinel;
sentinel->child = sentinel;
root = sentinel;
}
~TREE() {
if (NULL != sentinel) {
delete sentinel;
sentinel = NULL;
root = NULL;
}
}
NODE* search(int k)
{
NODE* x = root;
while (x != sentinel)
{
if (x->key == k) return x;
x = x->child;
}
return sentinel;
}
};
struct A {
TREE* t;
A() : t(new TREE()) {};
~A() {
if (NULL != t) {
delete t;
t = NULL;
}
}
};
int main()
{
TREE t;
t.search(1);
A embedded_tree;
embedded_tree.t->search(1);
}
However, since we're talking about C++, I'd suggest you to look to smart pointers and containers after you get familiar with manual memory management.

Copy constructor of polymorphed objects in a directed graph

I have a base class Node for a generic tree:
class Node {
public:
Node() {
parent = NULL;
name = "";
rule = NULLRULE;
childs = std::vector<Node*>();
};
void addChild(Node* child){
childs.push_back(child);
child->setParent(this);
};
void setParent(Node* p) {
this->parent = p;
}
virtual ~Node(){
if (childs.size() == 0) return;
// remove duplicate childs
// since we allow having same child.
std::sort(childs.begin(), childs.end());
childs.erase(std::unique(childs.begin(), childs.end()), childs.end());
for(unsigned int i = 0; i < childs.size(); i++) {
delete childs[i];
}
}
And I have derived class NodeSquare, NodeCircle etc... All the node formed a tree in the following class:
class Tree {
Tree() {};
~Tree() {
delete root;
};
void BFS(){};
etc...
Node* root;
}
How do I define a copy constructor for the Tree class? I am passing the tree through reference, that's why I need a copy constructor ...
processTree(Tree& t) {
t = Tree();
}
Tree(const Tree & copy)
{
if(copy != *this)
{
//to do
}
}
A copy constructif hais this signature , then if the scope you assign your data like a normal constructor the statement is for safety but you can use à list initializer.

C++ reversePrint Linked List Recursively

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.

Queue Data structure app crash with front() method

I am implementing a queue data structure, but my app crashes. I know I am doing something wrong with Node pointer front or Front() method of queue class
#include <iostream>
using namespace std;
class Node
{
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node * getNext() { return nextNode; };
void setNext(Node * nextNode) { this->nextNode = nextNode; };
private:
int object;
Node * nextNode;
};
class queue{
private:
Node *rear;
Node *front;
public:
int dequeue()
{
int x = front->get();
Node* p = front;
front = front->getNext();
delete p;
return x;
}
void enqueue(int x)
{
Node* newNode = new Node();
newNode->set(x);
newNode->setNext(NULL);
rear->setNext(newNode);
rear = newNode;
}
int Front()
{
return front->get();
}
int isEmpty()
{
return ( front == NULL );
}
};
main()
{
queue q;
q.enqueue(2);
cout<<q.Front();
system("pause");
}
You're using uninitialized pointers on several occasions.
Enqueue refers to rear->setNext(). If the queue is empty, rear is uninitialized, leading to crashes.
Front returns the node by some Node member-function without checking for a non-null pointer. Why not simply return the *front pointer?
None of your classes have a constructor. Your pointers aren't even NULL-pointers, they're just uninitialized. That's asking for troubles.
My advice:
Give both classes a constructor.
When calling ANY Node member-function, check for valid pointers.
Use less Node member-functions; returns raw pointers when you can.

c++ doubly linked list with null object model

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) {
}