Node Class
As part of the tree implementation you should implement a Node class. Each node should contain a Customer object, pointers to left and right children and (optionally) the parent.
So, currently I have a customer class such that:
class Customer {
public:
Customer(void);
Customer(string,char,int);
};
In my node class how can I create a customer object while linking the two files?
Do I just include the following in my node header file?
#include "Customer.h"
class Node {
public:
//Customer class
class Customer {
public:
Customer(void);
Customer(string,char,int);
}
Node(void); //default constructor
Node(string,char,int); //Node constructor with customer details
Node* left;
Node* right;
Node* parent;
};
In the node.cpp file to pass in the values to the node:
//Constructor
Node::Node(string x, char y, int z) {
lastName = x;
firstInitial = y;
balance = z;
}
How do I pass the values of the customer object to the node construct?
Do I just include the following in my node header file?
No. You just use an object of type Customer in Node.
#include "Customer.h"
class Node {
public:
Node(void); //default constructor
Node(string,char,int); //Node constructor with customer details
Node* left;
Node* right;
Node* parent;
Customer customer;
};
Implement the constructors as:
Node::Node() : left(nullptr),
right(nullptr),
parent(nullptr),
customer() {}
Node::Node(string x, char y, int z) : left(nullptr),
right(nullptr),
parent(nullptr),
customer(x, y, z) {}
You simply include the header as you did and then declare a Customer object in your Node class (private / protected / public, as you wish). When you'll declare a Node object, the first thing that is constructed are the objects inside your class, and only then the class itself. So, if you would have a coutin both constructors with the class name, when you'll be declaring a Node object, you'll see:
Customer's constructor
Node's constructor
Also, if you want to specify how to construct the Customer object inside the Node constructor, you can use the list of initialization
class Node
{
public:
Customer obj;
Node(string,char,int);
}
and then define the Node constructor like this in your .cpp file:
Node :: Node(string x,char y,int z) : obj(x, y, z) {
}
this is just an example. You can use static values when initializing obj or you could also get more parameters for Node constructor and so on.
Related
In c++ liked list Why we have to write node pointer like node* without specifying int, double etc. and we can also declare new node pointers in main without using any node class declaration.
class Node {
public:
int data;
Node* next;
};
If its any different kind of pointer then what it is called?
In your code
class Node {
public:
int data;
Node* next;
};
there is only one kind of node, and it has an int for data. That is why you don't need to write Node<int> or Node<double>. But you could change your code
template <typename T>
class Node {
public:
T data;
Node<T>* next;
};
This is called a template, and instead of only having an int for the data you can have any type. But now you have to say what that type is when you declare a variable. E.g.
Node<double>* ptr = new Node<double>();
I'm trying to create a linked list that stores a pointer to a binary tree,
The binary tree class is a subclass derived from a generic TreeNode class which I made.
The TreeNode class has it's AddNode method implemented (just as a dummy, but it is should be callable), but when I try to invoke that method from a subclass of TreeNode I am getting the following error:
Cannot initialize object parameter of type 'TreeNode' with an expression of type: 'std::__shared_ptr_access<ArtistPlaysNode>,__gnu_cxx::_S_atomic, false, false>::element_type'(aka 'ArtistPlaysNode')
Here is the relevant part of the TreeNode class:
// TreeNode.h
class TreeNode {
protected:
int key;
int height;
shared_ptr<TreeNode> father;
shared_ptr<TreeNode> left;
shared_ptr<TreeNode> right;
public:
explicit TreeNode(int key);
TreeNode(int key, shared_ptr<TreeNode> father, shared_ptr<TreeNode> left, shared_ptr<TreeNode> right);
virtual StatusType AddNode(shared_ptr<TreeNode> node);
};
// TreeNode.cpp
StatusType TreeNode::AddNode(shared_ptr<TreeNode> node) {
return INVALID_INPUT;
}
Here is ArtistPlaysNode:
// ArtistPlaysNode.h
class ArtistPlaysNode : public TreeNode {
private:
int artistId;
shared_ptr<SongPlaysNode> SongPlaysTree;
shared_ptr<MostPlayedListNode> ptrToListNode;
public:
ArtistPlaysNode(int artistId);
ArtistPlaysNode(int artistId, shared_ptr<SongPlaysNode> ptrToSongPlaysTree, shared_ptr<MostPlayedListNode> ptrToListNode);
int GetArtistId();
};
Here is the linked list, called MostPlayedListNode:
// MostPlayedListNode.h
class MostPlayedListNode {
private:
int numberOfPlays;
shared_ptr<ArtistPlaysNode> artistPlaysTree;
shared_ptr<ArtistPlaysNode> ptrToLowestArtistId;
shared_ptr<SongPlaysNode> ptrToLowestSongId;
shared_ptr<MostPlayedListNode> previous;
shared_ptr<MostPlayedListNode> next;
public:
// Create the first node in the list (0 plays)
MostPlayedListNode(int numOfPlays);
// Create a new node with a new highest number of plays
MostPlayedListNode(int numOfPlays, shared_ptr<MostPlayedListNode> previous);
// Create a new node with a number of plays between to values (1<2<3)
MostPlayedListNode(int numOfPlays, shared_ptr<MostPlayedListNode> previous, shared_ptr<MostPlayedListNode> next);
bool AddArtist(shared_ptr<ArtistPlaysNode> artistNode);
};
And here is the function where the error occurs:
// MostPlayedListNode.cpp
bool MostPlayedListNode::AddArtist(shared_ptr<ArtistPlaysNode> artistNode) {
if (ptrToLowestArtistId) {
// There are already artists stored in this linked list
this->artistPlaysTree->AddNode(artistNode); // -->>> this line throws the error.
return true
} else {
this->artistPlaysTree = artistNode;
return true;
}
return false;
}
I tried overriding the AddNode method inside ArtistPlaysNode, but that didn't work and made the compiler complain about being unable to cast from one pointer to the other.
Trying to search online for an answer didn't bring up any relevant results
Ok so in short, the error was caused by a lack of Forward Declarations.
Notice that the ArtistPlaysNode class has a shared_ptr of type MostPlayedListNode and of type SongPlaysNode as it's members.
And at the same time, the MostPlayedList class has a shared_ptr of type 'ArtistPlaysNode' and of type SongPlaysNode as it's members.
In addition, both ArtistPlaysNode and SongPlaysNode are derived from the TreeNode class.
This creates a scenario where these classes have members of the other type, in an almost cyclic fashion.
This usually causes errors of the type:
expected class name before '{' token. as seen in this question
Or it may cause an error of the type:
'NAME' was not declared in this scope as seen in enter link description here
In order to solve this issue, we need to either make sure everything a class, function or header relies on is declared before it is being used.
Or we need to provide the compiler with forward-declarations, these will allow the compiler to recognize that class, without its' complete definition being available.
In the case of my code, the fix was adding forward declarations in the class files of MostPlayedListNode, SongPlaysNode and ArtistPlaysNode.
for example, the top portion of the updated MostPlayedListNode.h file:
using std::shared_ptr;
using std::make_shared;
class ArtistPlaysNode; // this is a forward declaration
class SongPlaysNode; // this is a forward declaration
class MostPlayedListNode {
private:
int numberOfPlays;
shared_ptr<ArtistPlaysNode> artistPlaysTree;
shared_ptr<ArtistPlaysNode> ptrToLowestArtistId;
shared_ptr<SongPlaysNode> ptrToLowestSongId;
shared_ptr<MostPlayedListNode> previous;
shared_ptr<MostPlayedListNode> next;
public:
And the updated ArtistPlayesNode.h file:
using std::shared_ptr;
using std::make_shared;
class SongPlaysNode; // this is a forward declaration
class MostPlayedListNode; // this is a forward declaration
class ArtistPlaysNode : public TreeNode {
private:
int artistId;
shared_ptr<SongPlaysNode> SongPlaysTree;
shared_ptr<MostPlayedListNode> ptrToListNode;
public:
In conclusion, while writing certain data structures, forward-declarations are important in order for the compiler to recognize all of the necessary objects, if they're not already defined when they are needed by the object referencing them.
In my code I needed forward-declarations to account for Mutual Recursion, but that might not always be the case.
Let us assume that we have a class called Node which has a member called sequence and id. We want to print the sequence of the Node in many differnt ways. Instead of adding the print functions directly into the Node class, we put them into a seperate class called NodePrinter. Each Node, needs to have a "working" NodePrinter in any case.
Which implies that:
Node has a NodePrinter * printer member
Every constructor of Node needs to create a new NodePrinter
My idea now was to create a BaseNode and move the NodePrinter into that one. It has only one constructor, which takes a Node as an input and assigns it to the NodePrinter:
#include <iostream>
#include <string>
using namespace std;
class NodePrinter;
class Node;
class BaseNode
{
public:
BaseNode() = delete;
BaseNode(Node * node);
~BaseNode();
NodePrinter * printer;
};
class Node: public BaseNode
{
public:
Node(string sequence): BaseNode(this), sequence(sequence){}
Node(int id, string sequence): BaseNode(this), sequence(sequence), id(id){}
int id;
string sequence;
};
class NodePrinter
{
private:
Node * node;
public:
NodePrinter() = delete;
NodePrinter(Node * node): node(node){}
void print_node()
{
std::cout<<node->sequence<<endl;
}
};
BaseNode::BaseNode(Node * node)
{
node->printer = new NodePrinter(node);
}
BaseNode::~BaseNode()
{
delete printer;
printer = nullptr;
}
int main()
{
Node node("abc");
node.printer->print_node();
return 0;
}
Thereby each node is forced to call BaseNode(this) and the resources get allocated.
Is this reasonable, or is this whole approach already twisted from the start? Is there a better way to do this?
One thing that seems odd to me is that the printer depends on an instance of Node, shouldn't it be possible for a single printer to print multiple nodes? And I also wouldn't have Node depend on a NodePrinter either, because then you can't print the same node with multiple printers.
Anyhow, if you really need to keep the 1-to-1 correspondence, the simplest way is to just initialize the NodePrinter directly where the member variable is declared in Node:
#include <iostream>
#include <memory>
#include <string>
class Node;
class NodePrinter
{
private:
Node * node;
public:
NodePrinter() = delete;
NodePrinter(Node * node): node(node){}
void print_node();
};
class Node
{
public:
Node(std::string sequence) : sequence(std::move(sequence)){}
Node(int id, std::string sequence) : id(id), sequence(std::move(sequence)) {}
int id;
std::string sequence;
std::unique_ptr<NodePrinter> printer = std::make_unique<NodePrinter>(this);
};
void NodePrinter::print_node()
{
std::cout<< node->sequence << '\n';
}
int main()
{
Node node("abc");
node.printer->print_node();
return 0;
}
Live demo on wandbox.
For the implementation of linked list which is better
Using structure
#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
};
Using class
class ListNodeClass
{
private:
ItemType Info;
ListNodeClass * Next;
public:
ListNodeClass(const ItemType & Item, ListNodeClass * NextPtr = NULL):
Info(Item), Next(NextPtr)
{
};
void GetInfo(ItemType & TheInfo) const;
friend class ListClass;
};
typedef ListNodeClass * ListNodePtr;
Or is their any better way for doing linked list in C++ ?
The only one thing which class and struct makes differ in C++ is the default interface. if you write:
struct MyStruct
{
int a;
}
and:
class MyClass
{
int a;
}
the only one difference is a field in both them. In MyStruct field a is public and in MyClass field a is private. Of course you can manipulate them using public and private keywords in structs and classes both.
If you are programming in C++ you should use classes.
A linked list is one thing, its nodes are another thing. The nodes are part of the implementation of the list. They should not be visible in the interface of a list so their form doesn't really matter. I would do this
class List
{
private:
struct Node
{
int data;
Node* next;
};
public:
...
};
I'm interested in doing something like the following to adhere to a Null Object design pattern and to avoid prolific NULL tests:
class Node;
Node* NullNode;
class Node {
public:
Node(Node *l=NullNode, Node *r=NullNode) : left(l), right(r) {};
private:
Node *left, *right;
};
NullNode = new Node();
Of course, as written, NullNode has different memory locations before and after the Node class declaration. You could do this without the forward declaration, if you didn't want to have default arguments (i.e., remove Node *r=NullNode).
Another option would use some inheritence: make a parent class (Node) with two children (NullNode and FullNode). Then the node example above would be the code for FullNode and the NullNode in the code above would be of type NullNode inheriting from Node. I hate solving simple problems by appeals to inheritence.
So, the question is: how do you apply Null Object patterns to recursive data structures (classes) with default arguments (which are instances of that same class!) in C++?
Use extern:
extern Node* NullNode;
...
Node* NullNode = new Node();
Better yet, make it a static member:
class Node {
public:
static Node* Null;
Node(Node *l=Null, Node *r=Null) : left(l), right(r) {};
private:
Node *left, *right;
};
Node* Node::Null = new Node();
That said, in both existing code, and amendments above, you leak an instance of Node. You could use auto_ptr, but that would be dangerous because of uncertain order of destruction of globals and statics (a destructor of some global may need Node::Null, and it may or may not be already gone by then).
I've actually implemented a recursive tree (for JSON, etc.) doing something like this. Basically, your base class becomes the "NULL" implementation, and its interface is the union of all interfaces for the derived. You then have derived classes that implement the pieces- "DataNode" implements data getters and setters, etc.
That way, you can program to the base class interface and save yourself A LOT of pain. You set up the base implementation to do all the boilerplate logic for you, e.g.
class Node {
public:
Node() {}
virtual ~Node() {}
virtual string OutputAsINI() const { return ""; }
};
class DataNode {
private:
string myName;
string myData;
public:
DataNode(const string& name, const string& val);
~DataNode() {}
string OutputAsINI() const { string out = myName + " = " + myData; return out; }
};
This way I don't have to test anything- I just blindly call "OutputAsINI()". Similar logic for your whole interface will make most of the null tests go away.
Invert the hierarchy. Put the null node at the base:
class Node {
public:
Node() {}
virtual void visit() const {}
};
Then specialize as needed:
template<typename T>
class DataNode : public Node {
public:
DataNode(T x, const Node* l=&Null, const Node* r=&Null)
: left(l), right(r), data(x) {}
virtual void visit() const {
left->visit();
std::cout << data << std::endl;
right->visit();
}
private:
const Node *left, *right;
T data;
static const Node Null;
};
template<typename T>
const Node DataNode<T>::Null = Node();
Sample usage:
int main()
{
DataNode<char> a('A', new DataNode<char>('B'),
new DataNode<char>('C'));
a.visit();
return 0;
}
Output:
$ ./node
B
A
C