How to declare the nested classes correctly? [closed] - c++

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
Following code is a implemention of Binary Tree, coming from a C++ data structure text.
I canot compile the code successfully, getting some error messages. Mainly, the error lines comes from the last two of the code. How to fix this problem?
My IDE is CODE::BLOCK 12.11.
#include<iostream>
#include<list>
using namespace std;
typedef int Elem;
struct Node
{
Elem elt;
Node *par;
Node *left;
Node *right;
Node():elt(),par(NULL),left(NULL),right(NULL){}
};
class Position
{
private:
Node *v;
public:
Position(Node *_v=NULL):v(_v){}
Elem &operator*(){return v->elt;}
Position left()const{return Position(v->left);}
Position right()const{return Position(v->right);}
Position parent()const{return Position(v->par);}
bool isRoot()const{return v->par==NULL;}
bool isExternal()const{return v->left==NULL&&v->right==NULL;}
friend class LinkedBinaryTree;
};
typedef std::list<Position> PositionList;
class LinkedBinaryTree
{
protected:
struct Node; //This line is by me, the text merely tell you "insert Node declaration here. . ." I don't know whether this line is correct or not.
public:
class Position; // Also by me, the text merely tell you "insert Position declaration here. . ." I don't know wwhether this line is correct or not.
public:
LinkedBinaryTree();
int size()const;
bool empty()const;
Position root()const;
PositionList positions()const;
void addRoot();
void expandeExternal(const Position& p);
protected:
void preorder(Node* v,PositionList& pl)const;
private:
Node* _root;
int n;
};
LinkedBinaryTree::LinkedBinaryTree():_root(NULL),n(0){}
int LinkedBinaryTree::size()const{return n;}
bool LinkedBinaryTree::empty()const{return size()==0;}
LinkedBinaryTree::Position LinkedBinaryTree::root()const{Position(_root);} //canot compile successfully, this error messages is : C:\Users\user\Documents\aa\main.cpp|58|error: return type 'class LinkedBinaryTree::Position' is incomplete
void LinkedBinaryTree::addRoot(){_root=new Node;n=1;} //canoot compile successfully, this error message is C:\Users\user\Documents\aa\main.cpp|59|error: invalid use of incomplete type 'struct LinkedBinaryTree::Node'
There are many error messages, I select one of them to represent the error messages.

This:
class LinkedBinaryTree {
protected:
struct Node;
is called a forward declaration (of Node). It tells the compiler there is a type with that name, but it is not a definition of a class. You cannot create an instance of a type, unless its definition is visible. A forward declaration is not a definition.
If you had written:
class LinkedBinaryTree {
protected:
struct Node { /* ... */ };
Then you would be able to create a Node.
The forward declaration of a nested class is generally useful when you have codependent types, or you prefer to order declarations in a specific way.
The forward declaration is useful to tell the compiler there is a type with that name, so it can understand your intent before it is used:
class LinkedBinaryTree {
protected:
struct Node;
void foo(Node*);
struct Node { /* ... */ };
In this case, a pointer does not require physical dependence, so the name is enough to satisfy the compiler when it sees the declaration of foo.
Also note that your forward declaration declares a Node and Position in the class' scope, so the compiler takes it to mean that void preorder(Node* v,PositionList& pl)const; uses the types local to the class; e.g. void LinkedBinaryTree::preorder(LinkedBinaryTree::Node* v, LinkedBinaryTree::PositionList& pl)const;, rather than the Position and Node declared in the global namespace in your code sample.

Nested declaration should normally happen inside the class, like this:
#include<iostream>
#include<list>
using namespace std;
class LinkedBinaryTree
{
protected:
typedef int Elem;
struct Node
{
Elem elt;
Node *par;
Node *left;
Node *right;
Node():elt(),par(NULL),left(NULL),right(NULL){}
};
public:
class Position
{
private:
Node *v;
public:
Position(Node *_v=NULL):v(_v){}
Elem &operator*(){return v->elt;}
Position left()const{return Position(v->left);}
Position right()const{return Position(v->right);}
Position parent()const{return Position(v->par);}
bool isRoot()const{return v->par==NULL;}
bool isExternal()const{return v->left==NULL&&v->right==NULL;}
friend class LinkedBinaryTree;
};
typedef std::list<Position> PositionList;
public:
LinkedBinaryTree();
int size()const;
bool empty()const;
Position root()const;
PositionList positions()const;
void addRoot();
void expandeExternal(const Position& p);
protected:
void preorder(Node* v,PositionList& pl)const;
private:
Node* _root;
int n;
};
LinkedBinaryTree::LinkedBinaryTree():_root(NULL),n(0){}
int LinkedBinaryTree::size()const{return n;}
bool LinkedBinaryTree::empty()const{return size()==0;}
LinkedBinaryTree::Position LinkedBinaryTree::root()const{Position(_root);} //canot compile successfully, this error messages is : C:\Users\user\Documents\aa\main.cpp|58|error: return type 'class LinkedBinaryTree::Position' is incomplete
void LinkedBinaryTree::addRoot(){_root=new Node;n=1;}

Related

C++ forget to declare variable type causes error

I'm confused why the following code cannot compile because of the following bug: 'rootLevel' was not declared in this scope.
In my understanding, the struct NodeLevel is declared and defined before class Solution, is this not a sufficient condition for this class to be available to the Solution class?
Thanks!
struct NodeLevel{
int level;
BinaryTreeNode * node;
NodeLevel(int val, BinaryTreeNode * x) : level(val), node(x) {}
};
class Solution {
public:
vector<vector<int>> levelOrder(BinaryTreeNode* root) {
queue<NodeLevel> q;
rootLevel = NodeLevel(0, root);
q.push(rootLevel);
/*
do some stuff with the queue
*/
}
};
The compiler is correct, you did not declare the variable rootLevel.

Using or not using new for creation of a class in another

I have been solving a question, Dijkstra's Algorithm, in C++. I've implemented it using adjacency list.
So I have a class for a node, a class for a minHeap, and a class for the Graph.
class node
{
int vertex,weight;
node *next;
friend class Graph;
friend class minHeap;
public:
node();
node(int,int);
};
node::node(){
vertex=weight=0;
next=0;
}
node::node(int v,int wt){
vertex=v;
weight=wt;
next=0;
}
Do I define the minHeap class this way (without a friend function) and create an object in the getDijkSP() function normally, which allows me to use the object only in that function?
class minHeap
{
node *heap;
int heapSize,capacity,*pos;
public:
minHeap(int);
void addElement(node);
node extractMin();
void minHeapify(int);
void decreaseKey(int,int);
};
minHeap::minHeap(int cap){
heap=new node[capacity=cap];
heapSize=-1;
pos=new int[cap]();
} //eliminating other methods
class Graph
{
node **adjList;
int v;
bool *visited;
public:
Graph(int);
void addEdge(int,int,int);
void removeEdge(int,int);
bool existsEdge(int,int);
void getDijkSP();
};
Graph::Graph(int vertices){
adjList=new node*[v=vertices];
for(int i=0;i<v;i++)
adjList[i]=NULL;
}
void Graph::getDijkSP(){
minHeap hp(v); //here
hp.addElement(node(0,0));
for(int i=1;i<v;i++)
hp.addElement(node(i,INT_MAX));
while(!hp.isempty()){
node temp=hp.extractMin();
cout<<temp.vertex<<" "<<temp.weight<<endl;
for(node *current=adjList[temp.vertex];current;current=current->next)
hp.decreaseKey(current->vertex,current->weight+temp.weight);
}
}
(OR) Do I define the minHeap class with a friend function, so that I can create an object of the minHeap class using the new keyword? (And this helps me define the minHeap object in the scope of the Graph class, so that I can use it in all of its functions for other capabilities as well.)
class minHeap
{
node *heap;
int heapSize,capacity,*pos;
friend class Graph; //say like this
public:
minHeap(int);
void addElement(node);
node extractMin();
void minHeapify(int);
void decreaseKey(int,int);
};
minHeap::minHeap(int cap){
heap=new node[capacity=cap]();
heapSize=-1;
pos=new int[cap]();
}
class Graph
{
node **adjList;
int v;
bool *visited;
minHeap *hp; //and do this
public:
Graph(int);
void addEdge(int,int,int);
void removeEdge(int,int);
bool existsEdge(int,int);
void getDijkSP();
};
Graph::Graph(int vertices){
adjList=new node*[v=vertices];
for(int i=0;i<v;i++)
adjList[i]=NULL;
hp=new minHeap(v); //dynamic allocation
}
void Graph::getDijkSP(){
hp->addElement(node(0,0));
for(int i=1;i<v;i++)
hp->addElement(node(i,INT_MAX));
while(!hp->isempty()){
node temp=hp->extractMin();
cout<<temp.vertex<<" "<<temp.weight<<endl;
for(node *current=adjList[temp.vertex];current;current=current->next)
hp->decreaseKey(current->vertex,current->weight+temp.weight);
}
}
I have read this and a few other articles, but specifically want to know the advantages, disadvantages and the appropriateness of both the methods for such similar kinds of questions.
I've provided the constructors for the classes for better clarity.
Short answer would be NO. I would suggest you to read up on smart pointers and rewrite this whole mess. In C++ there is no real reason to use manual allocation in so simple project as this ever.
Also instead of assigning 0 or NULL to a pointer use nullptr, which is C++ symbol only for null pointers unlike the previous mentioned C values that are actually just a int 0 which may cause some unintentional errors.
Edit in response to your comment:
So I've decided to rewrite your code using actual modern C++ instead of this C code with simple classes. In your whole example there are almost no pointers or dynamic allocations needed. I wasn't absolutely sure who exactly should own the actual nodes so from the example I assumed that the MinHeap should. Also I didn't get the point of MinHeap::pos and Graph::visited from what I could see. I can explain any part of that code in more detail, just ask which.
Here is the code:
class Node {
// Only friend class required if you insist on keeping members of Node private.
// If they aren't meant to change, consider declaring them as public and const.
template <unsigned Size> friend class Graph;
public:
Node(int v, int wt) : vertex(v), weight(wt) {}
private:
// Default values written in here right after declarations
// There is no need for a default constructor. You never call it anyway.
int vertex;
int weight;
Node* next = nullptr;
};
// Template parameter because of internal use of std::array.
// If the capacity shouldn't be constant, use std::vector and remove template.
template <unsigned Capacity>
class MinHeap {
public:
// No constructor needed
// ---------------------
// One small tip: write parameter names in function declarations
// even if they aren't needed there for better readability of your code.
void addElement(Node n) { /* impl */ }
Node extractMin() { /* impl */ }
unsigned capacity() { return Capacity; }
bool isEmpty() { return heap.isEmpty(); }
private:
// Default values written in here right after declarations
int heapSize = -1;
std::array<Node, Capacity> heap;
};
// Template parameter because of internal use of std::array.
// If the vertex count shouldn't be constant, use std::vector and remove template.
template <unsigned Vertices>
class Graph {
public:
// No constructor needed
// ---------------------
void getDjikSP() {
hp.addElement({0, 0});
for (unsigned i = 1; i < hp.capacity(); ++i)
hp.addElement({0, INT_MAX});
while (!hp.isEmpty()) {
Node tmp = hp.extractMin();
std::cout << tmp.vertex << " " << tmp.weight << std::endl;
for (Node* current = adjList[tmp.vertex]; current != nullptr; current = current->next)
hp.decreaseKey(current->vertex, current->weight + tmp.weight);
}
}
private:
// Default values written in here right after declarations
std::array<Node*, Vertices> adjList;
MinHeap<Vertices> hp;
};
There is still a lot of space for improvements of this code, for example the MinHeaP::extractMin should maybe return Node&& if it is removed from the heap or const Node& if it should return a reference to the top, etc. To address all the problems and inefficiencies this can still have I would need to see the full code with all functions.

Return value type does not match the function type CONST

Not sure why error is happening on this function when I made the variable length const on a different function
int list::length() const {
return length;
}
CPP File Above
Header file BELOW
class list {
private:
struct Node
{
int info;
Node *next;
};
int length;
Node *head;
public:
list();
list(const list& otherlist);
~list();
int list::length() const;
};
The first issue is that you are qualifying length() inside your class. Remove list::. The second issue is that your member variable length, and your member function length are conflicting, because they have the same name.
I'd rename your members so that they don't clash with the functions. Consider length_ and head_.
Edit: please also post compiler errors in the future, as it makes other readers' jobs a little easier :)

Class forward declaration leads to incomplete type

I have the following code:
class Node;
class Edge {
public:
//Edge(Node originnode,Node targetnode,int weight):OriginNode(originnode),TargetNode(targetnode),Weight(weight){};
//~Edge(){};
//Node getOriginNode() const { return OriginNode;};
//Node getTargetNode() const { return TargetNode;};
int getWeight() const { return Weight;};
Node OriginNode;
Node TargetNode;
int Weight;
};
class Node{
public:
std::string getName();
std::vector<Edge> getEdges();
};
when I am trying to compile the compiler claims that OriginNode and TargetNode have incomplete type. I have already forward declare the Node. How can I fix that?
You can't without providing a full definition of Node. You can alternatively declare pointers as members: Node* OriginNode.
I'd suggest you re-think your design though - does an Edge really have a Node. As in - does it have ownership over it? Can't a Node be shared between multiple edges? Also, Does a Node really contain multiple edges?
With boost::container you can change the order of the declarations because it support containers of incomplete types :
class Edge;
class Node{
public:
std::string getName();
boost::container::vector<Edge> getEdges();
};
class Edge {
public:
//Edge(Node originnode,Node targetnode,int weight):OriginNode(originnode),TargetNode(targetnode),Weight(weight){};
//~Edge(){};
//Node getOriginNode() const { return OriginNode;};
//Node getTargetNode() const { return TargetNode;};
int getWeight() const { return Weight;};
Node OriginNode;
Node TargetNode;
int Weight;
};
By the way, why do you want to return a value of the Edge vector when you get them from the Node and why do you store the value of the OriginNode and TargetNode inside the edge, you can use references or pointers instead (maybe I'm wrong, I don't know all your requirements).
You should reverse the order of declarations
class Edge;
class Node{
public:
std::string getName();
std::vector<Edge> getEdges();
};
class Edge {
public:
//Edge(Node originnode,Node targetnode,int weight):OriginNode(originnode),TargetNode(targetnode),Weight(weight){};
//~Edge(){};
//Node getOriginNode() const { return OriginNode;};
//Node getTargetNode() const { return TargetNode;};
int getWeight() const { return Weight;};
Node OriginNode;
Node TargetNode;
int Weight;
};
Nevertheless I consider that design of classes as very bad. Node is a primitive entity that should not contain a vector of Edge. Why should Node control the container?! The container is a more high -level generalization than Node. So it should be placed in a more high level compared with Node.

Changing where a function's behavior is described is causing an error?

I have the following class declaration (I've tried to remove as much excess code as possible):
class List {
public:
struct Node {
int value;
};
Node * findNode(unsigned int) {
return new Node;
}
};
This gives no error. However, as soon as I define the function "findNode" outside of the class, I get an error; here's the code:
class List {
public:
struct Node {
int value;
};
Node * findNode(unsigned int);
};
Node * List::findNode(unsigned int index) {
return new Node;
}
Now, when running the code, I get an error saying "LinkedList.cpp:9:1: error: 'Node' does not name a type".
I would appreciate any help in determining the problem.
Until the compiler encounters List:: it has no idea the Node you're talking about is a member of List. Change the definition to:
List::Node * List::findNode(unsigned int index) {
return new Node;
}
The "naked" Node inside the function is fine because by that time the compiler knows the function is a member of List.