I'm experiencing some problems with breaking my code to reusable parts using templates and inheritance. I'd like to achieve that my tree class and avltree class use the same node class and that avltree class inherits some methods from the tree class and adds some specific ones. So I came up with the code below. Compiler throws an error in tree.h as marked below and I don't really know how to overcome this. Any help appreciated! :)
node.h:
#ifndef NODE_H
#define NODE_H
#include "tree.h"
template <class T>
class node
{
T data;
...
node()
...
friend class tree<T>;
};
#endif
tree.h
#ifndef DREVO_H
#define DREVO_H
#include "node.h"
template <class T>
class tree
{
public: //signatures
tree();
...
void insert(const T&);
private:
node<T> *root; //missing type specifier - int assumed. Note: C++ does not support default-int
};
//implementations
#endif
avl.h
#ifndef AVL_H
#define AVL_H
#include "tree.h"
#include "node.h"
template <class T>
class avl: public tree<T>
{
public: //specific
int findMin() const;
...
protected:
void rotateLeft(node<T> *)const;
private:
node<T> *root;
};
#endif
avl.cpp (I tried separating headers from implementation, it worked before I started to combine avl code with tree code)
#include "drevo"
#include "avl.h"
#include "vozlisce.h"
template class avl<int>; //I know that only avl with int can be used like this, but currently this is doesn't matter :)
//implementations
...
Both tree.h and node.h try to include each other, the include guards will prevent one of them from seeing the other.
Instead of #include "tree.h" try forward declaring tree like:
template <class T>
class tree;
in node.h
EDIT: As sbi suggested in a comment, it makes more sense to forward declare tree in node.h than the other way around, since it's about granting tree access to node through a friend declaration.
Don't #include "tree.h" in "node.h".
Also, you've declared root in both the tree and avl classes. Qualify tree::root as protected and remove avl::root.
Your problem is that tree.h includes node.h and vice versa. I would not have thought it is necessary (or makes much sense) for the node to have to know about the tree or to grant it friendship, so I'd remove that.
The problem is because of the circular dependency of header files between tree.h and node.h . Since node.h includes tree.h, while compiling the tree class, compiler doesn't know what is the type of node. Since you are using it just for declaring a friend there is no need to include the header file tree.h in node.h
Related
I got an assignment where I am supposed to create a Linked list by using CRTP. I got some starting code/suggestion on how to define the classes in their respective header files. I have omitted some code below:
Link.h
#include <iosfwd>
template<class T>
class List;
template<class T>
class Link {
Link* next;
friend class List<T>;
public:
Link();
virtual ~Link() = default;
//etc...
List.h
#include "Link.h"
template<class T>
class List : public Link<T> {
public:
List();
T* First();
T* Last();
//Etc...
This code compiles without any errors. Now my question is about the two first lines in Link.h, template<class T> class List;. I experimented a little bit and realized that Link.h won't compile without that class definition beacuse of the friend class List<T> statement. But why can't I just write #include "List.h" and remove the inheritance inside List.h and just use that definition from the start? I have tried this of course and get the error
"error: 'List' is not a class template
friend class List<T>;"
it would look like this:
Link.h
#include <iosfwd>
#include "List.h"
template<class T>
class Link {
Link* next;
friend class List<T>;
public:
Link();
virtual ~Link() = default;
List.h
#include "Link.h"
template<class T>
class List {
public:
List();
T* First();
Try to use a unique template in one file only or in files that build upon each other sequentially, not equally. In your case, you should probably move all of your files to one. Your .h files seem to mirror each other, so your compiler would have go back and forth between your references, but they do so in order. Choose the order of precedence.
I have a class ID3 and a class Tree. An object of Class Tree is used in ID3 and its showing an error that Tree is not declared.
Code looks like
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <math.h>
#include <vector>
using namespace std;
class ID3 {
public:
string v[];
int x;
public:
double Hi(Tree data)
{
int y=x-1;
}
};
class Tree{
Tree();
}
You need to forward declare Tree before using it in ID3, otherwise the compiler doesn't know what Tree is:
class Tree;
class ID3 {
...
If you need to use an instance of Tree somewhere then you need to have the full definition of Tree before that point, for example:
class Tree {
Tree();
};
class ID3 {
...
double Hi(Tree data) {
// do something with 'data'
int y=x-1;
}
};
For more information about when to use forward declarations, see this Q&A.
In general, C++ is compiled from top to bottom. So if the class ID3 needs the class Tree, Tree must be defined before ID3. Just put the class Tree before ID3 and it should be fine.
Forward deceleration of Tree will do the job. At the point where you used Tree instance in ID3, the compiler knows nothing about your Tree class, compiling process goes from up to bottom.
I am attempting to create a dynamic memory for this class i have created:
#ifndef STACK_H
#define STACK_H
#include <stdexcept>
#include "Link.h"
template <class T>
struct stack{
Link<T> * head;
stack();
void push(T * data);
T* top();
T* pop();
void cleanup();
};
#endif
src file:
#include "stack.h"
#include <cstddef>
template <class T>
stack<T>::stack(){
head=nullptr;
}
driver:
#include "stack.h"
#include <iostream>
#include <memory>
int main(){
stack<double> oneStack();
stack<double> * oneStack2=new stack<double>;
}
When I compile the code I get the following error:
g++ -Wall driver.o Link.o stack.o -o driver.exe
driver.o: In function main':
driver.cpp:(.text+0x1c): undefined reference tostack::stack()'
for some reason using the new keyword is causing this error?
When you are writing template class, you need to define function in the same place where you declare it, so you should probably write it like this
#ifndef STACK_H
#define STACK_H
#include <stdexcept>
#include "Link.h"
template <class T>
struct stack{
Link<T> * head;
stack()
{
// Constructor code goes here
}
void push(T * data)
{
// Method code goes here
}
T* top()
{
// Method code goes here
}
T* pop()
{
// You get the idea
}
void cleanup()
{
// ...
}
};
#endif
The reason why compiler needs the template classes and functions to be declared and defined in the same place is that it actually generates a new class for every different set of templates parameters that are used in your code. So, imagine you have .h file with declaration of template class and it's methods, and you have a .cpp file where these methods are defined. The compiler tries to compile .cpp file into an .obj file that will later be used to link code into a single executable or library file. But it can't do so, because it doesn't have template parameters right now in this file, so it can't actually generate a concrete code for a concrete parameters. Something like this.
If you want a better insight, you can look here: http://isocpp.org/wiki/faq/templates#templates-defn-vs-decl
Here is my problem.
I have a Linked List class as follows:
#include <iostream>
#include "List.h"
template <class Elem>
class LList : public List<Elem> { //List is a virtual base class
protected:
Node <Elem> *head;
Node <Elem> *fence;
Node <Elem> *tail;
int leftCount;
int rightCount;
void init();
void removeAll();
public:
LList();
~LList();
//Rest of methods overridden from List class
//////
};
Then I have a class called SortedLList which inherits from LList as follows:
#include "LinkedList.h"
#include "Helper.h"
template <class Elem>
class SortedLList : public LList<Elem> {
protected:
Helper *helper;
public:
SortedLList();
~SortedLList();
bool insert(const Elem&); //Override insertion method from LList class
};
In the implementation of SortedLList (SortledLList.cpp):
#include "SortedLList.h"
template <class Elem>
SortedLList<Elem>::~SortedLList() {
removeAll();
}
template <class Elem>
bool SortedLList<Elem>::insert(const Elem &_e) {
fence = head;
//Rest of Code..
}
I am having a compiler error that says : Use of undeclared identifier removeAll(). Same thing for fence and head pointers are not being recognized. What did I do wrong?
Thank You.
Because your class is a template there are certain issues that can happen to confuse the compiler. You may think your code is straight forward and easy to understand, and in this case it is. Older compilers used to do their best to guess and compile this code.
However, newer compilers are more strict and fail on all versions of this type of code, in order to prevent programmers from relying on it.
What you need to do is use the this pointer when calling base class functions. That makes the call unambiguous and clear. That would look like this->removeAll().
Another option would be to use a full name qualification like LList<Elem>::removeAll(). I prefer using this because it is easier to read.
I'm having trouble with compiling my template class. This is my list.cpp
using namespace std;
template <class T>
List<T>::List()
{
length = 0;
}
template <class T>
List<T>::~List()
{
}
template <class T>
List<T> & List<T>::operator=(const List<T> & rhs)
{
List<T> hha;
return hha;
}
template <class T>
int List<T>::size()
{
return length;
}
ANd this is my list.h
#ifndef _LIST_H_
#define _LIST_H_
#include <iterator>
#include <ostream>
using namespace std;
template <class T>
class List
{
private:
class ListNode
{
public:
ListNode();
ListNode(const T element);
ListNode *next;
T data;
};
public:
// big3
List();
~List();
List<T> & operator=(const List<T> & rhs);
int size();
bool empty();
void print(ostream & os) const;
private:
ListNode * head;
ListNode * tail;
int length;
};
#include "list.cpp"
#endif
when I run g++ list.cpp
I get errors
expected constructor, destructor, or type conversion before ‘<’ token
for definitions of constructor, destructor, and operator...
I don't know what seems to be wrong
The template implementation goes in the header.
It is a bit of a hack but it is how it is done.
The problem you currently encounter is that you list.cpp doesn't include you list.h: the compiler sees a couple of definitions for things which aren't declared, yet. You can fix this problem by including list.h at the top of your file:
#include "list.h"
...
However, this will essentially lead to a problem coming: if you actually want to use your List<T> with some type, the compiler will need to see the template definition where the class template is used. That is, typically you will implement your templates in the header file. The alterntaive is to implement templates in an implementation file and explicitly instantiating the types it is to be used with. This is quite reasonable for some templates but for something intended to be used for an unknown number of types this isn't practical.
BTW, you are using names which you are not allowed to touch: names starting with an underscore followed by a capital letter are reserved for the C++ implementation, i.e. the compiler and the standard library. Names using two consecutive underscores anywhere are also reserved.
Since list.hpp doesn't get #included in list.cpp, the compiler doesn't know about the template definition in that header when you try to compile list.cpp.
You compile list.cpp, that defines your list member functions. But it doesn't contain the template class declaration - that is in the header.
I see you include cpp in your list header. This will sort of work if you include the list header in some other cpp file and make sure list.cpp will not be compiled as a separate compilation unit.
What I mean is i.e. file main.cpp:
#include "list.h"
int main()
{}
Then compile this with g++ main.cpp.
Usually you just want to avoid cpp files when using templates altogether. Just stuff everything in the header and include that. Or alternatively I would at least rename your list.cpp to list.impl or some other name. This way one might be less tempted to actually try to compile that file directly.