template <class Type>
class Node
{
public:
Node ()
{
}
Node (Type x, Node* nd)
{
data = x;
next = nd;
}
Node (Type x)
{
data = x;
next = NULL;
}
~Node (void)
{
}
Node (const Node* & nd)
{
data = nd->data;
next = nd->next;
}
Node & Node::operator = (const Node* & nd)
{
data = nd->data;
next = nd->next;
}
T data;
Node* next;
};
Do I replace every Node* with
Node*<Type>
I tried replacing it and tried running something like
Node* temp = myq.head;
but it says argument list for class template "Node" is missing. I'm not really sure how to work with Templates when I need the Node class itself being part of it
Every declaration of Node will need a type in <>.
For
Node* temp = myq.head;
it depends on what myq.head is defined as. If it's defined as Node<int>* then temp also has to be defined as Node<int>* temp. You always have to have the <> with template objects.
If you wanted to have Node* without knowing the type, you could use inheritance. Have a templated TypedNode class that inherits from a non-template Node class. You would be able to pass all those TypeNode<> objects around with Node*, but you wouldn't be able to get the value of the nodes back out without knowing their type.
I don't recommend this but If you really want to make nodelists with mixed types you'll need to track the types by either
Include an enum type in the base class that defines the type stored in the node, and define typedNode for each class, setting the enum in it's constructor, or returning it from a virtual method.
RTTI, Run Time Type Information http://en.wikipedia.org/wiki/Run-time_type_information
Related
I've been attempting to create a node class which mimics a node on a graph. Currently, storage of the predecessor and successor nodes are stored via a node pointer vector: std::vector<Node*> previous. The vectors for the predecessor/successor nodes are private variables and are accessible via setters/getters.
Currently, I am dealing with updating the pointer values when adding a new node. My current method to update the predecessor/successor nodes is through this method (the method is the same for successor/previous nodes, just name changes):
void set_next(std::vector<Node*> new_next) {
this->next.clear();
for (Node* node : new_next) {
this->next.push_back(node);
}
}
This works for the current node but I was wondering the best way to update the new_next nodes that are passed in, especially the most 'C++'-esque way to accomplish this. I have previously written a method which adds individual nodes to the successor/predecessor vector:
void add_next(Node* new_node, bool one_way = false) {
this->next.pushback(new_node);
if (!one_way) {
new_node->add_prev(this, one_way = true);
}
}
The one_way variable was used to determine the depth(?) of the add_next() call. If it is true, it will add to the successor set and then add to the predecessor set of new_node. Since the boolean value is set to false when the new_node->add_next() method call occurs, it will only add to the predecessor set and not attempt to call add_next()/add_prev() again. This solution does work, but I'd rather not have the one_way variable and would prefer that the method would be private.
Here is the structure of the class currently:
class Node {
private:
std::vector<Node*> previous;
std::vector<Node*> next;
boost::any data;
public:
std::vector<Node*> get_previous()
void set_previous(std::vector<Node*> new_previous)
std::vector<Node*> get_next()
void set_next(std::vector<Node*> new_next)
void add_prev(Node* new_node, bool one_way = false)
void add_next(Node* new_node, bool one_way = false)
}
Avoiding the one_way parameter, it seems my best solution would be to just create an add_next/add_prev method that only updates the current node, not the passed node, unlike the solution above. With this solution, when adding new nodes, I could call the inverse of the add_next/add_prev on the new node. However, I have an inkling there may be a better solution for this.
Thank you!
I think this should get you going (edge-cases left to you to figure out, if any):
template<typename T>
class Node {
// Everything made public for debugging purposes, change this to fit your needs
public:
std::vector<Node<T>*> previous;
std::vector<Node<T>*> next;
T data;
Node(T val) {
data = val;
}
void set_next(std::vector<Node<T>*>& new_next);
};
template<typename T>
void Node<T>::set_next(std::vector<Node<T>*>& new_next) {
next = new_next;
for (Node<T>* node : new_next)
node->previous.push_back(this);
}
int main() {
// Little proof of concept where 0 is parent to 1, 2, 3
Node<int> one = 1;
Node<int> two = 2;
Node<int> three = 3;
Node<int> zero = 0;
std::vector<Node<int>*> new_next = { &one , &two, &three };
zero.set_next(new_next);
return 0;
}
To sum up the differences:
Use templates, boost::any is non standard and is all around terrible for this task.
Leverage operators (= makes a copy of std::vectors).
Leverage reference types (this way you can modify the argument passed to your function).
I have linked list class that implements a node structure, like this:
template<class T>
class LinkedList
{
public:
struct Node {
T value;
Node *next;
};
int Length;
Node *head;
Node *tail;
LinkedList() {
Length = 0;
Node* head = nullptr;
Node* tail = nullptr;
}
};
I tried accessing the node Node structure from the driver file like so:
#include "LinkedList.h"
template<class T>
void foo(LinkedList<T> list) {
LinkedList<T>::Node* a = list.head; // does not work
LinkedList<int>::Node* b = list.head; // works (if T is int of course)
}
Using a template T does not work (it gives me "identifier not found" error message), while directly specifying the correct datatype works. Why is that? Is there a way to avoid the error?
Use typename LinkedList<T>::Node* a = ...
The problem is that not knowing what exactly T is, the compiler can’t be sure LinkedList<T>::Node is indeed a type (LinkedList could be specialized for T so the definition doesn’t help). You need to instruct it to treat it that way.
Trying to make a B inary S earch T ree (BST for short) using a template.
When I try to create a new instance of my BST I get an unexpected error. I hope the solution does not involve pointers since I would like to keep them at a minimum.
For now I have:
template <typename Type>
class BST { // The binary search tree containing nodes
private:
BSTNode<Type> *root; // Has reference to root node
public:
BST ();
bool add (int, Type);
};
And the Node type:
EDIT: When I cut out code to un-encumber text, I forgot the constructor, now it's been added
template <typename Type>
class BSTNode { // Binary Search Tree nodes
private:
int key; // we search by key, no matter what type of data we have
Type data;
BSTNode *left;
BSTNode *right;
public:
BSTNode (int, Type&);
bool add (int, Type);
};
EDIT2: Here is the actual constructor
template <typename Type>
BSTNode<Type>::BSTNode (int initKey, Type &initData) {
this->key = initKey;
this->data = initData;
this->left = NULL;
this->right = NULL;
}
I want to try and test if anything works / doesn't work
BSTNode<int> data = new BSTNode (key, 10);
And I get: Expected type specifier before BSTNode. I have no idea what I'm doing wrong, but one thing I do hope is I don't have to use data as a pointer.
BSTNode<int> data = new BSTNode<int> (key, 10);
Also does not work, seems it believes < int > is < & int> and it doesn't match
First, you need to fully specify the type on the RHS of the assignment, and, since you are instantiating a dynamically allocated node with new, the LHS should be a pointer:
BSTNode<int>* data = new BSTNode<int> (key, 10);
^ ^
If you don't need a node pointer, then use
BSTNode<int> data(key, 10);
Second, your BSTNode<T> class doesn't have a constructor taking an int and a Type, so you need to provide that too.
template <typename Type>
class BSTNode {
public:
BSTNode(int k, const Type& val) : key(k), data(val), left(0), right(0) { .... }
};
I have one semestral work (own double linked list) and our teacher want this definition of class DoubleList:
template <typename T> //just part of all methods
class DoubleList {
public:
DoubleList(void); //We HAVE TO follow this definitions
void AddFirst(const T &); //const!
T &AccessActual(void);
T RemoveFirst(void);
}
My question is, how can I define a node? AddFirst have const argument and other methods haven't. Data must be set in constructor and then they can't be changed. Is this task so limited or are here other ways to complete the task?
Here is my actual Node:
template <class U>
class Node{
Node<U> * next;
Node<U> * previous;
const U * data;
public:
Node(const U *data){ //
next = NULL;
previous = NULL;
this->data = data;
}
void SetNext(Node<U> *next) {
this->next = next;
}
Node<U> *GetNext(){ return next; }
void SetPrevious(Node<U> *previous) {
this->previous = previous;
}
Node<U> *GetPrevious(){ return previous; }
const U *GetData() { return data; }
};
In containers, it's usually better to have a copy of the data so change const U * data; to U data;
The Node constructor would be easier to use if it had this signature Node(const U& data). No pointers.
The GetData would also have to change. Return a reference. U& GetData().
It is dangerous to hold addresses of data items. If the user of the lists wants that functionality he can use a list that stored pointers (e.g. U=int*)
Your node class seems fine, although i would keep using template argument T instead of U, right now it is confusing.
Your AddFirst() method should simply create a new node and assign the correct next pointer to the new node and the correct prev pointer to the "old" first node and adjust the actual object? what does that refer to?
Your interface of nodes differs from this one returning a reference instead of a pointer. I find it quite strange that the AccessActual can always return an object, while when the list is empty this can be a nullptr??
example implementation:
void AddFirst(const T &)
{
Node<T>* newNode = new Node<T>(T);
Node<T>* current = &AccessActual(); // how can there be an actual when the list can be empty or is that impossible?
{
while( current.GetPrev() != nullptr )
{
current = *current.GetPrev();
}
current.SetPrev(newnode);
newnode->SetNext(current);
}
}
I dont know why I'm getting this error: list.cpp:127: error: ‘class List’ has no member named ‘curr’
template <class T>
List<T> List<T>::mixSplit()
{
List<T> * newList;
class List<T>::ListNode * curr = head;
newList->length=0;
newList->length-3;
newList->head = NULL;
newList->tail=NULL;
for (int count=0;count<1;count++)
newList->curr=newList->curr->next;
newList->head=newList->curr;
newList->tail=tail;
tail=newList->curr->prev;
tail->next=NULL;
newList->head->prev=NULL;
newList->tail->next=NULL;
return newList;
}
The error is occuring at
newList->curr=newList->curr->next;
When I do this:
class List<T>::ListNode * curr = head;
Shouldn't that allow for curr to be the head of newList?
Edit:
Here is the class definition:
template <class T>
class List
{
private:
class ListNode
{
public:
// constructors; implemented in list_given.cpp
ListNode();
ListNode(T const & ndata);
// member variables
ListNode * next;
ListNode * prev;
const T data; // const because we do not want to modify node's data
};
The class List doesn't have a member curr, that's what the error says. I'm pretty sure that the class does indeed not have that member.
The fact that there's another variable in a different scope with the same name - is irrelevant.
Use typename as instead of class:
typename List<T>::ListNode * curr = head; //correct
//class List<T>::ListNode * curr = head; //incorrect
It is one example where you cannot use class in place of typename.
error: list.cpp:127: error: ‘class List’ has no member named ‘curr’
From the error, it is clear that the definition of the template is in .cpp file. That is another reason of the problem. You cannot provide the definition of template in another file. The declaration and definition should be in the same file. So move all the definition to the header file.
The problem is that there is no member like, curr inside List<T>! You misunderstood that, curr is a member of List<T>::ListNode!!.
Just declaring a class inside class doesn't mean that all the inner class members delegated to outer class too and vice verse. You need to have ListNode* curr; inside List<T> to accomplish this.
After solving compiler errors you will end up solving runtime errors because there are several other problems with your class. For example,
List<T> * newList; // dangling/uninitialized pointer
class List<T>::ListNode * curr = head; // curr is unused and pointing to something unknown
You must initialize newList = new List<T>; to use the pointer. Or you can declare an automatic object as List<T> newList;.