I am getting a few errors that I don't know about and have spent entirely to much time pulling my hair out. Here is my Header:
#ifndef MYBSTREE_H
#define MYBSTREE_H
#include "abstractbstree.h"
#include "MyBSTreeFunc.h"
using namespace std;
template<typename T>
class TreeNode
{
public:
T m_data;
TreeNode* m_right;
TreeNode* m_left;
};
template<typename T>
class MyBSTree:public AbstractBSTree<T> //LINE 18
{
private:
TreeNode<T>* m_root;
public:
void MyBSTree();
int size() const;
bool isEmpty() const;
int height() const;
const T& findMax() const;
const T& findMin() const;
int contains(const T& x) const;
void clear();
void insert(const T& x);
void remove(const T& x);
void printPreOrder() const;
void printPostOrder() const;
void print() const;
};
#endif
And my implementation file:
Line 1-6
void MyBSTree()
{
m_root -> m_data = NULL;
m_root -> m_right = NULL;
m_root -> m_left = NULL;
}
Line 13-21
template<typename T>
bool MyBSTree<T>::isEmpty() const
{
if (m_root== NULL)
return true;
else
return false;
}
Line 28-35
template < typename T >
const T& MyBSTree<T>::findMax() const
{
TreeNode* p = m_root;
while(p -> m_right != NULL)
p = p -> m_right;
return p;
}
The error for line 3 in the implementation says 'm_root' was not declared in this scope. But it's cool with lines 4 and 5. I'm guessing because m_data isn't a pointer? I don't know.
Next, Line 14, and 21, and quite a few others say that it expected an initializer before the '<' token. I assume they are all the same issue so I only put a few here.
Finally, it says for line 18 in the header: "template struct MyBSTree redeclared as a different kind of symbol." It then says Line 1 of my implementation is a previous declaration of 'void MyBSTree". I am assuming those go together.
Thanks for all the help.
You need to fix your constructor declaration:
template < typename T >
classMyBSTree
{
... // some stuff
public:
MyBSTree(); // no return type
... // some stuff
};
You alse need to fix your constructor:
template < typename T >
MyBSTree::MyBSTree() // proper ctor definition
{
m_root -> m_data = T(); // use the initializer for that data type
m_root -> m_right = NULL;
m_root -> m_left = NULL;
}
Lines 1-6: You've define a standalone function in the .cpp named void MyBSTree(). This is not part of the class. It's also bad that you named the function the same as your class. It looks like you want this to be your constructor, in which case you need this (I won't include the template stuff, as it's not the issue):
// in .h
class MyBSTree {
public:
MyBSTree(); // No void
}
// in .cpp
// Uses MyBSTree namespace.
MyBSTree::MyBSTree() { /* initialize your pointers etc */ }
This seems to be your main issue, and may fix the other problems too.
The reason the compiler cannot find m_roots is because your function is not part of the class. You would fix this by putting your function into the class scope with operator :: (e.g. myBSTree::myBSTree(){};)
Template functions cannot be placed in separate files from their class, you need to define all of your template class and function in the same file. Move the implementation of your functions into your header file.
Related
This is a function to find the maximum amount of left nodes. I do realize that there is already a thread for that:
Count number of left nodes in BST
but I don't want pointers in my main file. So I am trying to find a slightly different approach.
bst<int>::binTreeIterator it;
int findMax(bst<int>::binTreeIterator it)
{
int l = 0, r;
if (!(it.leftSide() == NULL)) {
l += 1 + findMax(it.leftSide());
}
if (!(it.rightSide() == NULL)) {
r = findMax(it.rightSide());
}
return l;
}
my problem is with the leftSide()/rightSide() function; How do I implement them so that it returns an iterator object that points to the left side/ right side of the iterator "it" object?
template <class Type>
typename bst<Type>::binTreeIterator bst<Type>::binTreeIterator::leftSide()
{
}
Edit:
template <class Type>
class bst
{
struct binTreeNode
{
binTreeNode * left;
binTreeNode * right;
Type item;
};
public:
class binTreeIterator
{
public:
friend class bst;
binTreeIterator();
binTreeIterator(binTreeNode*);
bool operator==(binTreeNode*);
bool operator==(binTreeIterator);
binTreeIterator rightSide();
binTreeIterator leftSide();
private:
binTreeNode * current;
};
bst();
bst(const bst<Type>&);
const bst& operator=(const bst<Type>&);
~bst();
void insert(const Type&);
void display(); // TEST
binTreeIterator begin();
binTreeIterator end();
private:
binTreeNode * insert(binTreeNode*, const Type&);
void inorder(binTreeNode*);
void destroyTree(binTreeNode*);
void cloneTree(binTreeNode*, binTreeNode*);
binTreeNode * root;
};
This very simple snipped of code should do the trick already:
template <class Type>
typename bst<Type>::binTreeIterator bst<Type>::binTreeIterator::leftSide()
{
return current->left;
}
As you did not declare the iterator's constructor explicit, it will get called automatically from the pointer to left/right returned.
So I have this Binary Search tree that I want to define with templates. those are the headers:
template <class T>
class BSNode
{
public:
BSNode(T data);
BSNode(const BSNode& other);
virtual ~BSNode();
virtual BSNode* insert(T value);
BSNode& operator=(const BSNode& other);
bool isLeaf() const;
T getData() const;
BSNode* getLeft() const;
BSNode* getRight() const;
bool search(T val) const;
int getDepth(const BSNode& root) const;
void printNodes() const;
protected:
T _data;
BSNode* _left;
BSNode* _right;
int _count; // if there are duplicated items.
int BSNode::getCurrNodeDistFromInputNode(const BSNode* node) const; // help func to get depth.
};
But for some reason I always get an "unable to match definition" error in the getters or "use of class templates requires arguement list"
for example, this code yields an "unable to match definition" error.
template<class T>
BSNode* BSNode<T>::getLeft() const
{
return this->_left;
}
template<class T>
BSNode* BSNode<T>::getRight() const
{
return this->_right;
}
This code yields "use of class templates requires argument list":
template<class T>
BSNode* BSNode<T>::insert(T value)
{
// check where should insert the node - right or left
if (value < this->_data)
{
if (_left) // if there is already left son
{
_left = _left->insert(value); // recursive call on the left son
}
else
{
_left = new BSNode(value); // add the node as left son
return *this;
}
}
else if (value > this->_data)
{
if (_right) // if there is already right son
{
_right = _right->insert(value); // recursive call on the right son
}
else
{
_right = new BSNode(value); // add the node as right son
return *this;
}
}
else //value == this->_data
{
this->_count++;
return *this;
}
return *this;
}
I am pretty sure my problem lies with the signatures, but still i post the full code. Can somebody help me understand why am I getting this problems and what am I doing wrong?
Unless the compiler already knows you're inside the context of BSNode you need to provide the template arguments - so for example
template<class T>
BSNode<T>* BSNode<T>::getLeft() const
{
return this->_left;
}
Yes, this feels a bit repetitive. You can make it less verbose by defining the member functions inside the class definition. (Although some people also dislike that for stylistic reasons.)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Hello I am working on a project for data structures and I am stuck.
The project is to build a templated linked list class and a nested iterator class, inside a headerfile only. I do not understand how to use the iterator class inside of the templated LinkedList class. I am not sure about iterators in general. The methods declared are all needed to run the tests that will be ran. I am currently stuck on initializing 'LinkedList* prev' and next in the constructor. Please help! How do I initialize something that is templated? the compiler wants to know what data type I think? Thanks for your time
The error is on the constructor declaration in the class LinkedList
EDITED "invalid initialization of non-const reference of type 'std::basic_string char&' from an rvalue of type 'int'" is the error message
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
template <typename T> class LinkedList
{
private:
LinkedList<T>* head;
int size;
T element = NULL;
LinkedList<T>* prev;
LinkedList<T>* next;
public:
class Iterator
{
friend class LinkedList<T>;
private:
public:
Iterator();
T operator*() const;
Iterator& operator++();
bool operator==(Iterator const& rhs);
bool operator!=(Iterator const& rhs);
};
LinkedList<T>():prev(0), next(0){} //HERE is the ERROR????////////
Iterator begin() const
{
// Iterator tempIterator = LinkedList<T>();
//
// return tempIterator->front;
return NULL;
}
Iterator end() const{return NULL;}
bool isEmpty() const;
T getFront() const;
T getBack() const;
void enqueue(T newElement)
{
LinkedList<T>* newElem = new LinkedList<T>();
newElem->element = newElement;
if(front == 0)
{
front = newElem;
}
else
{
back->next = newElem;
}
back = newElem;
listSize++;
}
void dequeue()
{
LinkedList<T>* tempElem = new LinkedList<T>();
if(front == 0){
cout << "List is empty!" << endl;
}
else
{
tempElem = front;
front = front->next;
cout << "the element dequeued: " << tempElem->element;
delete tempElem;
}
}
void pop();
void clear();
bool contains(T element) const;
void remove(T element);
};
#endif /* LINKEDLIST_H_ */
The constructor syntax is wrong.
LinkedList():prev(0), next(0){}
This is the correct constructor syntax. Once the template class and parameters are declared, in the template declaration, the name of the template alone, without the parameters, refers to the template itself, inside its scope. Similarly, if you were to explicitly define a destructor, it would be:
~LinkedList() { /* ... */ }
If you wanted to only declare the constructor inside the template declaration:
LinkedList();
and then define it outside of the template declaration, then the correct syntax would be:
template<typename T>
LinkedList<T>::LinkedList() :prev(0), next(0){}
i tried to build up my own linked list class and got a problem with the = operator overloading. as far as i know, we should use const parameter when overloading the assignment operator, say using linked_list<T>& operator=( const linked_list<T>& a). however, the complier gave me errors unless i put linked_list<T>& a instead. the complier would stop at
if(this->head==a.front()), giving me Error
11 error C2662: 'linked_list<T>::front' : cannot convert 'this' pointer from 'const linked_list<T>' to 'linked_list<T> &'
below are the details.
#ifndef _LINKED_LIST_H_
#define _LINKED_LIST_H_
template <class T>
struct node
{
T data;
node<T>* next;
};
template <class T>
class linked_list
{
private:
node<T>* head;
public:
linked_list<T>();
linked_list<T>(const linked_list<T>& a);
~linked_list<T>();
linked_list<T>& operator=(const linked_list<T>& a);
bool isEmpty();
int size() const;
void insert_front(T a);
void insert_end(T a);
void erase_end();
void erase_front();
void print() const;
void erase(node<T>* a);
node<T>*& front()
{
node<T>* ptr = new node<T>;
ptr = head;
return ptr;
}
void setFront(node<T>* a);
};
#endif
template <class T>
linked_list<T>& linked_list<T>::operator=(const linked_list<T>& a)
{
if (this->head == a.front()) // the error mentioned happened here. however,
// if no const in the parameter, it would be
// no error
{
return *this;
}
while (head != nullptr) erase_front();
node<T>* copy;
copy = a.front();
while (copy->next != nullptr)
{
insert_end(copy->data);
copy = copy->next;
}
return *this;
}
anybody can help? thanks.
When an accessor returns a reference to an owned structure, it's usually a good idea to implement two versions: One which is non-const and returns a non-const reference, and one which is const and returns a const reference. That way it can be used in both mutating and non-mutating contexts. front() would be a good candidate for this.
Though a side note -- you probably don't want to expose your nodes in the public linked_list interface, particularly non-const references to them. That's the sort of thing to encapsulate entirely in the class.
The problem is that front() is not a const member function, and you're trying to call it on a const instance.
First of all I would like to thank in advance anyone who answers this question. Your help is greatly appreciated. This is my first time posting here, so please forgive me if I post with bad etiquette.
My question is about the method prototype:
void copySubtree(Node<T> * & target, Node<T> * const & original);
and when I call copySubtree() later in combineTrees(). As the code is currently, it builds. But what I originally had was:
void copySubtree(Node<T> * & target, const Node<T> * & original);
which gave me the error:
error C2664: 'RootedBinaryTree<T>::copySubtree' : cannot convert parameter 2 from 'RootedBinaryTree<T>::Node<T> *const ' to 'const RootedBinaryTree<T>::Node<T> *&'
I know that when you put const before the data type in the parameter it prevents you from modifying said parameter in your method, but I do not know what it does when you put it after the data type, nor am I certain that my code building with the placement of const after the data type was not just a fluke. What does placing const after a data type do? Will my code have horrible runtime problems the way it is currently written?
[Also: I am in the process of trying to write the rooted binary tree template class method definitions (which is why some of the methods are empty, and there are some random notes to myself in the comments). So I apologize for any inconvenience caused by that.]
Here is the relevant code:
RootedBinaryTree.h
#ifndef ROOTEDBINARYTREE_H
#define ROOTEDBINARYTREE_H
template <class T>
class RootedBinaryTree
{
private:
template <class T>
struct Node
{
T nodeData;
Node<T> * leftChild;
Node<T> * rightChild;
};
Node<T> * root;
Node<T> * currentPosition;
void copySubtree(Node<T> * & target, Node<T> * const & original);
void deleteSubtree(Node<T> * n);
public:
RootedBinaryTree(const T & rootData);
RootedBinaryTree(const RootedBinaryTree<T> & original);
~RootedBinaryTree();
void toRoot();
bool moveLeft();
bool moveRight();
T getData() const {return currentPosition->nodeData;};
RootedBinaryTree<T> & operator=(const RootedBinaryTree<T> & RHS);
void combineTrees(const RootedBinaryTree<T> & leftTree, const RootedBinaryTree<T> & rightTree);
void setNodeData(const T & nodeData);
};
#endif
RootedBinaryTree.cpp
#ifndef ROOTEDBINARYTREE_CPP
#define ROOTEDBINARYTREE_CPP
#include "RootedBinaryTree.h"
template<class T>
void RootedBinaryTree<T>::copySubtree(Node<T> * & target, Node<T> * const & original)
{
// later add something here to delete a subtree if the node we are trying to assign to has children
// perhaps a deleteSubtree() method
target = new Node<T>;
if(original->leftChild != 0L)
{
copySubtree(target->leftChild, original->leftChild);
}
else
{
target->leftChild = 0L;
}
// ^^^ copy targets left (and right) children to originals
if(original->rightChild != 0L)
{
copySubtree(target->rightChild, original->rightChild);
}
else
{
target->rightChild = 0L;
}
target->nodeData = original->nodeData;
}
template <class T>
void RootedBinaryTree<T>::deleteSubtree(Node<T> * n) // Done
{// Assumes that n is a valid node.
if(n->leftChild != 0L) deleteSubtree(n->leftChild); // Delete all nodes in left subtree
if(n->rightChild != 0L) deleteSubtree(n->rightChild); // Delete all nodes in right subtree
delete n;
}
template <class T>
RootedBinaryTree<T>::RootedBinaryTree(const T & rootData) // Done
{
root = new Node <T>;
root->leftChild = 0L;
root->rightChild = 0L;
root->nodeData = rootData;
currentPosition = root;
}
template <class T>
RootedBinaryTree<T>::RootedBinaryTree(const RootedBinaryTree<T> & original)
{
}
template <class T>
RootedBinaryTree<T>::~RootedBinaryTree()
{
deleteSubtree(root); // root will be valid because of our constructor and other methods
root = currentPosition = 0L;
}
template <class T>
void RootedBinaryTree<T>::toRoot() // Done
{
currentPosition = root;
}
template <class T>
bool RootedBinaryTree<T>::moveLeft() // Done
{
if(currentPosition->leftChild == 0L) return false;
currentPosition = currentPosition->leftChild;
return true;
}
template <class T>
bool RootedBinaryTree<T>::moveRight() // Done
{
if(currentPosition->rightChild == 0L) return false;
currentPosition = currentPosition->rightChild;
return true;
}
template <class T>
RootedBinaryTree<T> & RootedBinaryTree<T>::operator=(const RootedBinaryTree<T> & RHS)
{
}
template <class T>
void RootedBinaryTree<T>::combineTrees(const RootedBinaryTree<T> & leftTree, const RootedBinaryTree<T> & rightTree)
{ // Copies leftTree into root's left tree and rightTree into root's right tree.
if(root->leftChild != 0L) deleteSubtree(root->leftChild);
if(root->rightChild != 0L) deleteSubtree(root->rightChild);
copySubtree(root->leftChild, leftTree.root);
copySubtree(root->rightChild, rightTree.root);
}
template <class T>
void RootedBinaryTree<T>::setNodeData(const T & nodeData)
{
currentPosition->nodeData = nodeData;
}
#endif
Thanks again!
The rule is that const attaches itself to the thing on its left, and if there's nothing to the left, it attaches itself to the thing on the right. So in this case, we have:
const Node *p; // p is a pointer to a const Node
Node const *p; // same again, p is a pointer to a const Node
Node * const p; // p is a const pointer to a (mutable) Node
const Node * const p; // p is a const pointer to a const Node
Node const * const p; // same again, p is a const pointer to a const Node
Most people write const Type, because that's how we tend to think of them, but some people prefer writing Type const because of this rule.