#ifndef _CBINARYTREE_H_
#define _CBINARYTREE_H_
#include <iostream>
using namespace std;
template <class T>
class CBinaryTree;
template <class T>
class CTreeNode
{
private:
T m_tNodeElement;
CTreeNode *m_pLeftChild,
*m_pRightChild;
public:
CTreeNode():m_tNodeElement(0),m_pLeftChild(NULL),m_pRightChild(NULL) { }
CTreeNode(T new_node_element, CTreeNode *parent_node):m_tRootElement(new_element) {
m_pLeftChild = m_pRightChild = NULL;
parent_node->m_pLeftChild = m_pLeftChild;
parent_node->m_pRightChild = m_pRightChild;
}
~CTreeNode() { delete m_pLeftChild;
delete m_pRightChild; }
};
template <class T>
class CBinaryTree : public CTreeNode
{
private:
T *m_pRoot;
T element;
int m_nTreeHeight;
public:
CBinaryTree():m_nTreeHeight(0),m_pRoot(NULL) {
CTreeNode(element, m_pRoot);
}
~CBinaryTree() { delete m_pRoot; }
};
#endif
🔒 Locked
Binary Tree Class Template Help
Advertisement
Original Post
Hello all. I'm tring to create a binary tree for some practice (which trees and OOP) and hopefuly make one good enough to replace a few data structures. Here is my class template: Compiling... main.cpp c:\Documents and Settings\Justin Ward\My Documents\Visual Studio Projects\Coding For Fun\CBinaryTree.h(42) : error C2512: 'CTreeNode' : no appropriate default constructor available I was woundering why am I getting this error. Its probably cause of the way I'm implementing my class heirarchy with the tree node and the binary tree class. I appricate all the help. Thank you alot ahead of time.
Well, this is the constructor you are trying to call:
The current problem is that you are passing in a T * instead of a CTreeNode< T > *.
Might I ask what this is for?
jfl.
CTreeNode(T new_node_element, CTreeNode *parent_node):m_tRootElement(new_element) { m_pLeftChild = m_pRightChild = NULL; parent_node->m_pLeftChild = m_pLeftChild; parent_node->m_pRightChild = m_pRightChild; }The current problem is that you are passing in a T * instead of a CTreeNode< T > *.
Might I ask what this is for?
jfl.
Quote:
Original post by jflanglois
Well, this is the constructor you are trying to call:CTreeNode(T new_node_element, CTreeNode *parent_node):m_tRootElement(new_element) { m_pLeftChild = m_pRightChild = NULL; parent_node->m_pLeftChild = m_pLeftChild; parent_node->m_pRightChild = m_pRightChild; }
The current problem is that you are passing in a T * instead of a CTreeNode< T > *.
Might I ask what this is for?
jfl.
Do you mean he's passing a CTreeNode * instead of a CTreeNode
I believe you want:
CTreeNode is not a type, it is a template. Instantiations of that template are types. Also a call to a constructor within the body of another constructor will construct a temporary instance, it will not call the base class constructor. Base class constructors must be called inside the initializer list.
Enigma
#ifndef _CBINARYTREE_H_ #define _CBINARYTREE_H_ #include <iostream>using namespace std;template < class T >class CBinaryTree;template < class T >class CTreeNode{ private: T m_tNodeElement; CTreeNode * m_pLeftChild; CTreeNode * m_pRightChild; public: CTreeNode() : m_tNodeElement(0), m_pLeftChild(NULL), m_pRightChild(NULL) { } CTreeNode(T new_node_element, CTreeNode * parent_node) : m_tNodeElement(new_node_element) { m_pLeftChild = m_pRightChild = NULL; parent_node->m_pLeftChild = m_pLeftChild; parent_node->m_pRightChild = m_pRightChild; } ~CTreeNode() { delete m_pLeftChild; delete m_pRightChild; }};template < class T >class CBinaryTree : public CTreeNode< T >{ private: CTreeNode< T > * m_pRoot; T element; int m_nTreeHeight; public: CBinaryTree() : CTreeNode< T >(element, m_pRoot), m_nTreeHeight(0), m_pRoot(NULL) { } ~CBinaryTree() { delete m_pRoot; }};#endifCTreeNode is not a type, it is a template. Instantiations of that template are types. Also a call to a constructor within the body of another constructor will construct a temporary instance, it will not call the base class constructor. Base class constructors must be called inside the initializer list.
Enigma
Quote:
Original post by Agony Quote:
Original post by jflanglois
Well, this is the constructor you are trying to call:CTreeNode(T new_node_element, CTreeNode *parent_node):m_tRootElement(new_element) { m_pLeftChild = m_pRightChild = NULL; parent_node->m_pLeftChild = m_pLeftChild; parent_node->m_pRightChild = m_pRightChild; }
The current problem is that you are passing in a T * instead of a CTreeNode< T > *.
Might I ask what this is for?
jfl.
Do you mean he's passing a CTreeNode * instead of a CTreeNode*? (So basically all that is lacking is the . The whole type of the parameter needs to be known, including template parameters.)
No, I mean that he is passing in m_pRoot, which is T *, to the constructor which needs a CTreeNode * (or CTreeNode< T > * to be explicit). Actually, my suggestion will not fix the problem, because it has to do with CBinaryTree deriving from CTreeNode.
In any case, to the OP: You should read up a bit more on binary trees because, as it stands, your code is mixing concepts together (CBinaryTree is a CTreeNode, yet you include the idea of a root node in the CBinaryTree class).
jfl.
I understand binary trees I was just try to make the CTreeNode class be an object and have the CBinaryTree be an object that I guess would be a B-Tree of objects CTreeNode. And yea the passing CTreeNode * didn't fix it.
Thank you for all the help.
Thank you for all the help.
I don't mean to be rude or put you off, all the power to you (and anyone) for wanting to learn how it works but your code does have a number of issues and it maybe a result of not yet knowing enough C++ to tackle the problem.
To start with the first error you are getting is in reference to this:
There are two reasons why you are getting an error here
The other issues with your code are:
[Edited by - snk_kid on October 14, 2005 4:40:21 PM]
To start with the first error you are getting is in reference to this:
CBinaryTree():m_nTreeHeight(0),m_pRoot(NULL) { CTreeNode(element, m_pRoot); }There are two reasons why you are getting an error here
- CTreeNode is a class template yet when you inherit from it in CBinaryTree (which is also a class template) you are not passing the template typename parameter to it, i.e. this:
template <class T>class CBinaryTree : public CTreeNode { /* ... */ };
Should be this:template <class T>class CBinaryTree : public CTreeNode<T> { /* ... */ }; - The other problem is when you want to invoke a base constructor to initialize it's members with an alternative constructor instead of implicitly using the default constructor of the base you do it in the constructor initializer list not in the constructor's definition, i.e.:
derived(): base(...), ... {}
If the base is a template then you also need to give a type to it's template parameter.
The other issues with your code are:
- In the initializer list of the default constructor of CTreeNode the member m_tNodeElement is initialized to zero, this only makes sense for a very small set of types.
- The second, non default constructor of CTreeNode the parameter new_node_element is passed by value since we don't know what types will instantiate this this might end up being an expensive, redundant copy either always pass by constant reference for all types or use a technique called type traits to determine when to pass by value or constant reference and if your not sure how to go about this you could use boost::call_traits.
- In CBinaryTree you have a member called element yet you are already storing an element in CTreeNode what is the point of storing two copies? also you have a member called m_pRoot and it's of type T* i don't understand what purpose does this member serve.
- If you are going to store/use pointers to CTreeNode
that refer to instances of type CBinaryTree and you invoke delete on those pointers the behaviour is undefined by the standard but typically this will result in resource leaks, if you must do this then to make it work correctly and portably you need to make CTreeNode a polymorphic type and it's destructor virtual. - CBinaryTree (as is the case for CTreeNode) needs to define what means to copy & assign because as of current the defaults implicitly defined do a member-wise copy/assign of pointers therefore it's a shallow copy. If these classes are going to be used on there own as is you should probably provide a user-defined copy constructor and assignement operator or disable value/copy semantics by declaring them private/protected. If you have some main class that maintains the tree then ignore this and make sure the main class has explicitly defined copy semantics
- Dumping namespaces into global namespace is generally bad practice (especially in headers) as you risk the chances of name collisions, good C++ coders never do this except for rare occasions of syntax sugar.
- A binary tree is not very useful if doesn't order it's elements in some where when making insertions, therefore it needs some binary Predicate (C++ callable entity, hint to store a pointer to free-function, or functors, or bound pointer to member function) inorder to know whether to put a new element into the left or right sub-tree.
- In C++ it's not necessary to write custom plain binary search trees (but useful as a learning exercise) as the standard library provides containers such as std::(multi)set/map which use red-black trees which are binary search trees that are always mostly balanced trees.
[Edited by - snk_kid on October 14, 2005 4:40:21 PM]
Thank you for the comments, and no I don't take any of it to offence. Learning is learning and I'm always open to advice to better my C++ skills.
What do you mean by this:
"Dumping namepsaces into global namespace is generally bad practice as you risk the chances of name collisions, good C++ coders never do this except for rare occasions of syntax sugar."
I understand what the standard namespace is, are you implying that I should use the std:: instead of using namespace std;?
Edit: Curious are saying that I don;t really need to create a CTreeNode class, i should just keep it all in one class CBinaryTree?
What do you mean by this:
"Dumping namepsaces into global namespace is generally bad practice as you risk the chances of name collisions, good C++ coders never do this except for rare occasions of syntax sugar."
I understand what the standard namespace is, are you implying that I should use the std:: instead of using namespace std;?
Edit: Curious are saying that I don;t really need to create a CTreeNode class, i should just keep it all in one class CBinaryTree?
You might want to go through my previous post again as i made some corrections and fixed some spelling mistakes [lol].
Sometimes when i look back at some of my posts i think i sound like a right a*** [grin] but i'm not trying to be, i'm not really good with writing/explaining stuff.
Most of the time yes, not always though. The main point of namespaces are to avoid name collisions, if i use your code with mine and we have a function with the same name it causes ambiguity the compiler cannot know which one i want to use.
The alternative you suggested using i.e std::some_name is called full quantification it's definitely a millions times better than dumping all names in a named namespace into global namespace 99% of the time. However full quantification can be verbose and tedious too so you have alternative choices you can namespace aliases (give a name alias for a namespace) i.e.:
You can have using statements in virtually any place in C++, you can have a using statement in function scope and it's only visible there:
Well it's most definitely a good idea to seperate node types/classes from the main tree type/class but i'm not sure exactly what you are trying to accomplish with CBinaryTree inheriting from CTreeNode.
Quote:
Original post by LostSource
Thank you for the comments, and no I don't take any of it to offence. Learning is learning and I'm always open to advice to better my C++ skills.
Sometimes when i look back at some of my posts i think i sound like a right a*** [grin] but i'm not trying to be, i'm not really good with writing/explaining stuff.
Quote:
Original post by LostSource
What do you mean by this:
"Dumping namepsaces into global namespace is generally bad practice as you risk the chances of name collisions, good C++ coders never do this except for rare occasions of syntax sugar."
I understand what the standard namespace is, are you implying that I should use the std:: instead of using namespace std;?
Most of the time yes, not always though. The main point of namespaces are to avoid name collisions, if i use your code with mine and we have a function with the same name it causes ambiguity the compiler cannot know which one i want to use.
The alternative you suggested using i.e std::some_name is called full quantification it's definitely a millions times better than dumping all names in a named namespace into global namespace 99% of the time. However full quantification can be verbose and tedious too so you have alternative choices you can namespace aliases (give a name alias for a namespace) i.e.:
namespace foo = outer_namespace::nested_namespace;You can have using statements in virtually any place in C++, you can have a using statement in function scope and it's only visible there:
void foo() { using namespace std; // dump namespace in the scope of foo}void bar() { using std::cout; // dump only the name of cout into the scope of foo}Quote:
Original post by LostSource
Edit: Curious are saying that I don;t really need to create a CTreeNode class, i should just keep it all in one class CBinaryTree?
Well it's most definitely a good idea to seperate node types/classes from the main tree type/class but i'm not sure exactly what you are trying to accomplish with CBinaryTree inheriting from CTreeNode.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement