I'm new to C , and I have undertaken learning generics and advanced data structures.
I was able to create a parent class called Collection
that is extended by the LinkedList
class. In that, and in implementing most of the features I wanted, I succeeded.
However, the last feature that I would like to implement is a toLinkedList()
function from the parent class.
Collection.h
#include"LinkedList.h"
template <class E>
class Collection {
public:
...
LinkedList<E> toLinkedList();
};
LinkedList.h
#include "Collection.h"
template <class E>
class LinkedList : public Collection<E> {
public:
...
LinkedList<E> toLinkedList();
};
LinkedList.cpp
#include "LinkedList.h"
#include "Collection.h"
template <class E>
LinkedList<E> LinkedList<E>::toLinkedList() {
LinkedList<E> out = LinkedList<E>();
LinkedNode<E> current = head;
while (current != NULL) {
out.add(current);
current = current->next;
}
return *out;
}
The idea is that the LinkedList
and future data structures could all be converted into a LinkedList
object.
As far as I know, everything should be OK, however I am getting an error when I attempt to define the LinkedList<E> toLinkedList()
function:
no template named LinkedList<E>
CodePudding user response:
First of all, a quick warning: it turns out that modeling collections via inheritance often works out rather badly. Collections are all similar, but for inheritance to work, you need each derived collection to be a proper superset of the base class, and that turns out to be kind of difficult. For example, in Java they ended up having to decide that a Map
is not Collection
.
Getting to your specific question: rather than having the base Collection
class know how to convert some collection to a derived type such as LinkedList
, you probably want to reverse that, and have a LinkedList
know how to construct itself from a (pointer/reference to a)base Collection
instead.
This accomplishes a couple of useful things. In your approach, the base class needs to know about every derived class (a bad idea). In the reverse approach, every derived class has to know about the base class--but since it's a derived class, that's true regardless.
Second, it avoids a combinatorial explosion, where the base class not only has to know about every derived class, but (quite frequently) needs special code to deal more or less separately with both how to get data from the source and how to get data into the destination, so N collection types result in N different toDest
functions, each of which needs N different pieces of code to deal with the source of data.
But for real use, you probably shouldn't use any of the above. The C standard library already includes std::vector
, std::list
, std::forward_list
, std::deque
, std::stack
, std::queue
, std::map
, std::set
, and so on. These are already standardized, so people know how to use them, and they avoid inheritance, so you don't end up with problems like the one mentioned above, where Map
ends up as officially "not a collection".
CodePudding user response:
Do a forward declaration, like this. Also, don't forget include guards, virtual functions, etc.
Collection.h
#pragma once
template <class E> class LinkedList;
template <class E>
class Collection {
public:
...
virtual LinkedList<E> toLinkedList() = 0;
};
LinkedList.h
#pragma once
#include "Collection.h"
template <class E>
class LinkedList : public Collection<E> {
public:
...
LinkedList<E> toLinkedList();
};