I have a class called Node:
class Node {
private:
Node right;
Node left;
std::string value;
public:
Node(Node right, Node left, std::string value) {
this->right = right;
this->left = left;
this->value = value;
}
};
And I need to declare a private variable of type Node inside the Node class itself.
Is there any way to do this?
You must declare the members as being pointers to Node instances. Especially since you want to be able to set them to NULL, which can only be done with pointers:
class Node {
private:
Node* right;
Node* left;
std::string value;
public:
Node(Node* right, Node* left, std::string value) {
this->right = right;
this->left = left;
this->value = value;
}
};
When you are trying to declare a class with itself as a member like this, you need to use pointers to do so. If you didn't need pointers, then creating one node object would construct two node members, both of which have their own node members which would construct more nodes and so on. By using pointers, you effectively must explicitly link each pointer member to an object in the heap, which prevents an immediate stack overflow error.
class Node {
private:
Node* right;
Node* left;
std::string value;
public:
Node(Node right, Node left, std::string value) {
this.right = new Node(right.data);
this.left = new Node(left.data);
this.value = value;
}
~Node(){ delete left; delete right; }
};
Here's an example of how this might look. This won't compile as-is, but its a representation of the right idea. Make sure to initialze left or right to nullptr unless you explicitly assign it in construction and specify a destructor like in this example. Also don't forget "the big three" if needed.
Note that I changed your shorthand to a dot operator, as in this.right. Your compiler will probably understand what you mean, but the shorthand should only be used when accessing a pointers data, such as in something like right->data. In case you didn't know, right->data actually does the exact same thing as (*right).data. We use a shorthand operator because *right.data would fail because the dot operator has higher precedence than the dereference operator.
Related
I'm new to C++. I am initializing a class object Node in another class LCache. When I try to compile my code, I get the following error:
Line 22: Char 5: error: unknown type name 'left'
left -> next = right;
^
Below is the code I have written:
class Node{
public:
int k;
Node* prev;
Node* next;
Node (int key){
k=key;
prev=NULL;
next=NULL;
}
};
class LCache {
private:
Node* left = new Node(0);
Node* right = new Node(0);
left -> next = right;
right -> prev = left;
...
When I move left -> next = right; and right -> prev = left; inside a method in class LCache, the error goes away. Can you explain the reason here?
You can't perform non-declaration statements inside of a class declaration, like you are trying to do. You need to perform them inside of a class member function instead, or in this case inside of the class constructor (like you did with Node), eg:
class Node{
public:
int k;
Node* prev;
Node* next;
Node (int key){
k = key;
prev = NULL;
next = NULL;
}
};
class LCache {
private:
Node* left = new Node(0);
Node* right = new Node(0);
LCache() {
left->next = right;
right->prev = left;
}
~LCache() {
delete left;
delete right;
}
...
};
That being said:
NULL is deprecated in modern C++, use nullptr instead.
And you should use smart pointers whenever you have owned pointers that need freeing when they are done being used. Or better, just don't use objects dynamically when you don't actually need to.
Try something more like this instead:
class Node{
public:
int k;
Node* prev = nullptr;
Node* next = nullptr;
Node (int key) : k(key) {}
};
class LCache {
private:
std::unique_ptr<Node> left = std::make_unique<Node>(0);
std::unique_ptr<Node> right = std::make_unique<Node>(0);
LCache() {
left->next = right;
right->prev = left;
}
...
};
/* alternatively:
class LCache {
private:
Node left{0};
Node right{0};
LCache() {
left.next = &right;
right.prev = &left;
}
...
};
*/
You're trying to do an assignment in the declaration of the class type. That makes no sense!
You probably wanted to write things such as "assign to left's next field the value…" in some method of your code.
This far, this is plain invalid C++ – maybe go a little slower in your C++ intro. The step from "I write a C++ class and assign values to its fields" to "I build a graph" is non-negligible.
I'm trying to speed up a python routine by writing it in C++, then using it using ctypes or cython.
I'm brand new to c++. I'm using Microsoft Visual C++ Express as it's free.
I plan to implement an expression tree, and a method to evaluate it in postfix order.
The problem I run into right away is:
class Node {
char *cargo;
Node left;
Node right;
};
I can't declare left or right as Node types.
No, because the object would be infinitely large (because every Node has as members two other Node objects, which each have as members two other Node objects, which each... well, you get the point).
You can, however, have a pointer to the class type as a member variable:
class Node {
char *cargo;
Node* left; // I'm not a Node; I'm just a pointer to a Node
Node* right; // Same here
};
Just for completeness, note that a class can contain a static instance of itself:
class A
{
static A a;
};
This is because static members are not actually stored in the class instances, so there is no recursion.
No, but it can have a reference or a pointer to itself:
class Node
{
Node *pnode;
Node &rnode;
};
Use a pointer, & better initialized:
class Node {
char * cargo = nullptr;
Node * left = nullptr;
Node * right = nullptr;
};
Modern C++
It is a better practice to use smart-pointers (unique_ptr, shared_ptr, etc.), instead of memory allocations by 'new':
#include <string>
#include <memory> // For 'std::unique_ptr'
class Node {
public:
std::string cargo;
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
};
int main()
{
auto bt = std::make_unique<Node>();
(*bt).cargo = "Coffee";
(*bt).left = std::make_unique<Node>();
}
I am very new to smart pointers and I am trying to create a doubly tree where the child nodes are pointed from the parents by a unique pointer, and the children are pointing to the parents via raw pointer. So when A parent node gets destroyed the whole sub-tree will get destroyed in the process.
class Node {
private:
Node *parent;
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
public:
Node(Node* _left, Node* _right, Node* _parent);
};
Node::Node(Node* _left, Node* _right, Node* _parent) {
parent = &_parent;
//this is where the problem starts
}
I don't understand how to point to a new node that might have a tree I want to connect. If I use make_unique I believe that will create a new node Instead of preserving the tree.
I might be totally wrong about this since I just learned smart pointers about 4 days ago (Realistically enough time to learn something).
First of all, an empty tree is possible and a default constructed node will fit well.
Parent reference will be known at the time a node is attached so, child's node parent shall be updated once a node is set as left or right child of the current tree.
It might be a good idea to receive unique_ptr as you are taking ownership of the pointer you receive. Here is an example implementation:
class Node {
private:
Node *parent = nullptr;
std::unique_ptr<Node> m_left;
std::unique_ptr<Node> m_right;
public:
void left(std::unique_ptr<Node> child) {
m_left = std::move(child);
m_left->parent = this;
}
void right(std::unique_ptr<Node> child) {
m_right = std::move(child);
m_right->parent = this;
}
};
You will use it like the following:
int main()
{
auto tree = std::make_unique<Node>();
auto subtree = std::make_unique<Node>();
subtree->right(std::make_unique<Node>());
tree->right(std::make_unique<Node>());
tree->left(std::move(subtree));
return 0;
}
I'm pretty new to unique_ptr myself, hope someone will further correct me.
BTW don't use names hat that starts with _ for your identifies, they are reserved.
I don't think you can use:
Node(Node _left, Node _right, Node _parent);
This won't allow to build the tree node by node. Instead, use:
Node(Node* _left, Node* _right, Node* _parent);
That way, you can create the first node using:
Node firstNode(nullptr, nullptr, nullptr);
From there, you can build other nodes.
To build a simple tree, with three nodes as below
N1
/ \
N2 N3
you can use:
Node* N1 = new Node(nullptr, nullptr, nullptr);
Node* N2 = new Node(nullptr, nullptr, N1);
Node* N3 = new Node(nullptr, nullptr, N1);
N1->left = N2; // Use the equivalent member function.
N1->right = N3;
I believe that you want to make the parent, left and right child public. At least, this is how I have always implemented my nodes using a struct instead:
struct Node
{
Node(std::unique_ptr<Node> _parent = nullptr,
std::unique_ptr<Node> _left = nullptr, std::unique_ptr<Node> _right = nullptr) : parent(_parent), left(_left), right(_right) {}
std::unique_ptr<Node> parent;
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
};
Someone please correct me if I am wrong.
As you can see in the following code, I attempt to have some default arguments of the function "initialize" that are union. How to change the definition of the function "initialize" to make it compatible with C++ before C++ 11? Do I need to add some constructors to RedBlackPointer? If so, how?
template <typename T> class RedBlackNode{
protected:
union RedBlackPointer{
RedBlackNode *node;
struct{
unsigned value:1; // for color / other info
}flag;
}left, right, parent;
T key;
public:
void initialize(T key, RedBlackPointer left = {(RedBlackNode*)0},
RedBlackPointer right = {(RedBlackNode*)0},
RedBlackPointer parent = {(RedBlackNode*)0}){
this->key = key;
this->left = left; this->right = right;
this->parent = parent;
}
}
Indeed, the extended initialization lists are not available before C++11.
As long as you keep in mind that only ONE member in a union can be active at any time, you can easily solve the issue with a default constructor:
template <typename T> class RedBlackNode{
protected:
union RedBlackPointer{
RedBlackPointer() : node(0) { } // <==== default constructor
RedBlackNode *node;
struct{
unsigned value:1; // for color / other info
}flag;
}left, right, parent;
T key;
public:
void initialize(T key, RedBlackPointer left = RedBlackPointer(), //refer to default ctor
RedBlackPointer right = RedBlackPointer(),
RedBlackPointer parent = RedBlackPointer()){
this->key = key;
this->left = left; this->right = right;
this->parent = parent;
}
void show() {
cout<<left.node<<","<<right.node<<","<<parent.node<<","<<key<<endl;
}
}; // <=== ;
And here how to demonstrate that it works:
RedBlackNode<int> N;
N.initialize(5);
N.show();
Here a live demo and here with a compiler that rejected your initial code.
Additional comment:
One thing puzzles me: in your union you combine a pointer with a one bit flag.
This is not shoking per se: it could imagine it being a trick to avoid overhead of pointer allocation, when sometimes the value poitned to is small enough to be stored directly in the tree.
However in this case, it's not clear how you will know wich is the active member (i.e. when to use the pointer, and when to use the flag is used).
So I'd suggest you cross check that there is not a mistake / forgottoen element here.
I'm trying to speed up a python routine by writing it in C++, then using it using ctypes or cython.
I'm brand new to c++. I'm using Microsoft Visual C++ Express as it's free.
I plan to implement an expression tree, and a method to evaluate it in postfix order.
The problem I run into right away is:
class Node {
char *cargo;
Node left;
Node right;
};
I can't declare left or right as Node types.
No, because the object would be infinitely large (because every Node has as members two other Node objects, which each have as members two other Node objects, which each... well, you get the point).
You can, however, have a pointer to the class type as a member variable:
class Node {
char *cargo;
Node* left; // I'm not a Node; I'm just a pointer to a Node
Node* right; // Same here
};
Just for completeness, note that a class can contain a static instance of itself:
class A
{
static A a;
};
This is because static members are not actually stored in the class instances, so there is no recursion.
No, but it can have a reference or a pointer to itself:
class Node
{
Node *pnode;
Node &rnode;
};
Use a pointer, & better initialized:
class Node {
char * cargo = nullptr;
Node * left = nullptr;
Node * right = nullptr;
};
Modern C++
It is a better practice to use smart-pointers (unique_ptr, shared_ptr, etc.), instead of memory allocations by 'new':
#include <string>
#include <memory> // For 'std::unique_ptr'
class Node {
public:
std::string cargo;
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
};
int main()
{
auto bt = std::make_unique<Node>();
(*bt).cargo = "Coffee";
(*bt).left = std::make_unique<Node>();
}