0

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>

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Is this purely for fun, or do you intend to actually use this? For real use, C++ already has `std::list`, `std::vector`, and so on, so writing your own collections is *usually* counterproductive. Writing your own to explore the concepts can be fairly useful (such as giving you can opportunity to think through a better approach to the problem you're seeing right now). – Jerry Coffin Oct 04 '22 at 22:49
  • You can [forward declare](https://en.cppreference.com/w/cpp/language/class) `LinkedList`. I am assuming you aren't showing your actual code, because here, `LinkedList.h` and `Collection.h` both include each other. – Nelfeal Oct 04 '22 at 22:52
  • 1
    You have circular references between `Collection.h` and `LinkedList.h`, that will not bode well. Also, [you can't separate the implementation of `LinkedList` into `.h` and `.cpp` files](https://stackoverflow.com/questions/495021/) the way you are attempting to. – Remy Lebeau Oct 04 '22 at 22:54
  • 1
    Can and should are two different things. You _can_ do it, but your base class knowing about it’s derived types runs contrary to the goal of inheritance. – Taekahn Oct 04 '22 at 22:55
  • In general, a parent class has no idea of the contents of the child class. The parent class has no idea of the quantity of child classes either. You could implement a virtual method in the parent class and have the child class implement it. Be aware that the method would need to be implemented by all children. – Thomas Matthews Oct 04 '22 at 23:04
  • You need to post a [mre]. – relent95 Oct 05 '22 at 01:11

2 Answers2

0

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".

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 1
    Thank you for the reply! I suppose I should have mentioned that the collection class doesn't store any data on its own, simply just some shared functions between a few advanced data structures. Actually, I sorta limited it to the things that could apply to both 'maps' and 'lists', although I forgot about converting to the parent, so I will make sure to do that. I'm going to replace the function in the collection class with a LinkedList constructor with a collection as input. This whole exorcise is more about practice than about using it in a larger program. – Adam Dailey Oct 04 '22 at 23:24
0

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();
};
relent95
  • 3,703
  • 1
  • 14
  • 17