0

I'm trying to create a linked list that stores a pointer to a binary tree, The binary tree class is a subclass derived from a generic TreeNode class which I made.

The TreeNode class has it's AddNode method implemented (just as a dummy, but it is should be callable), but when I try to invoke that method from a subclass of TreeNode I am getting the following error:

Cannot initialize object parameter of type 'TreeNode' with an expression of type: 'std::__shared_ptr_access<ArtistPlaysNode>,__gnu_cxx::_S_atomic, false, false>::element_type'(aka 'ArtistPlaysNode')

Here is the relevant part of the TreeNode class:

// TreeNode.h
class TreeNode {
protected:
    int key;
    int height;
    shared_ptr<TreeNode> father;
    shared_ptr<TreeNode> left;
    shared_ptr<TreeNode> right;
public:
    explicit TreeNode(int key);

    TreeNode(int key, shared_ptr<TreeNode> father, shared_ptr<TreeNode> left, shared_ptr<TreeNode> right);

    virtual StatusType AddNode(shared_ptr<TreeNode> node);
};

// TreeNode.cpp
StatusType TreeNode::AddNode(shared_ptr<TreeNode> node) {
    return INVALID_INPUT;
}

Here is ArtistPlaysNode:

// ArtistPlaysNode.h
class ArtistPlaysNode : public TreeNode {
private:
    int artistId;
    shared_ptr<SongPlaysNode> SongPlaysTree;
    shared_ptr<MostPlayedListNode> ptrToListNode;
public:
    ArtistPlaysNode(int artistId);
    ArtistPlaysNode(int artistId, shared_ptr<SongPlaysNode> ptrToSongPlaysTree, shared_ptr<MostPlayedListNode> ptrToListNode);
    int GetArtistId();
};

Here is the linked list, called MostPlayedListNode:

// MostPlayedListNode.h
class MostPlayedListNode {
private:
    int numberOfPlays;
    shared_ptr<ArtistPlaysNode> artistPlaysTree;
    shared_ptr<ArtistPlaysNode> ptrToLowestArtistId;
    shared_ptr<SongPlaysNode> ptrToLowestSongId;
    shared_ptr<MostPlayedListNode> previous;
    shared_ptr<MostPlayedListNode> next;

public:
    // Create the first node in the list (0 plays)
    MostPlayedListNode(int numOfPlays);

    // Create a new node with a new highest number of plays
    MostPlayedListNode(int numOfPlays, shared_ptr<MostPlayedListNode> previous);

    // Create a new node with a number of plays between to values (1<2<3)
    MostPlayedListNode(int numOfPlays, shared_ptr<MostPlayedListNode> previous, shared_ptr<MostPlayedListNode> next);

    bool AddArtist(shared_ptr<ArtistPlaysNode> artistNode);
};

And here is the function where the error occurs:

// MostPlayedListNode.cpp
bool MostPlayedListNode::AddArtist(shared_ptr<ArtistPlaysNode> artistNode) {
    if (ptrToLowestArtistId) {
        // There are already artists stored in this linked list
        this->artistPlaysTree->AddNode(artistNode); // -->>> this line throws the error.
        return true
    } else {
        this->artistPlaysTree = artistNode;
        return true;
    }
    return false;
}

I tried overriding the AddNode method inside ArtistPlaysNode, but that didn't work and made the compiler complain about being unable to cast from one pointer to the other.

Trying to search online for an answer didn't bring up any relevant results

Mor Paz
  • 2,088
  • 2
  • 20
  • 38
  • C++ is not Java. Both of those shared pointers are of different types. – PaulMcKenzie Apr 29 '20 at 20:28
  • 1
    @PaulMcKenzie Thats not an issue. std::shared_ptrs are capable of up-casting: ArtistPlaysNode inherits from TreeNode. If they weren't, std::shared_ptrs wouldn't be of much use in patterns utilizing dynamic polymorphism. – Azam Bham Apr 29 '20 at 20:31
  • I suggest trying a minimal reproducible example. Cut this back until the error disappears, or you have something simple enough that you can post code that compiles apart from this error. – Jasper Kent Apr 29 '20 at 20:38
  • @AzamBham -- Maybe I got ahead of myself, but it certainly is an issue if the code posted is not what is actually being compiled. Taking what was posted and creating a much smaller example, [the error cannot be duplicated](http://coliru.stacked-crooked.com/a/f4bbeac23c82c4bf) – PaulMcKenzie Apr 29 '20 at 20:47
  • @PaulMcKenzie Agreed, I can't seem to duplicate the error either – Azam Bham Apr 29 '20 at 20:48
  • I tried following @JasperKent suggestion and create a more minimal project and the error doesn't appear again, I'll try and figure out what is the cause and hopefully provide an answer – Mor Paz Apr 29 '20 at 20:48

1 Answers1

0

Ok so in short, the error was caused by a lack of Forward Declarations.

Notice that the ArtistPlaysNode class has a shared_ptr of type MostPlayedListNode and of type SongPlaysNode as it's members. And at the same time, the MostPlayedList class has a shared_ptr of type 'ArtistPlaysNode' and of type SongPlaysNode as it's members.

In addition, both ArtistPlaysNode and SongPlaysNode are derived from the TreeNode class.

This creates a scenario where these classes have members of the other type, in an almost cyclic fashion.

This usually causes errors of the type:

expected class name before '{' token. as seen in this question

Or it may cause an error of the type:

'NAME' was not declared in this scope as seen in enter link description here

In order to solve this issue, we need to either make sure everything a class, function or header relies on is declared before it is being used.

Or we need to provide the compiler with forward-declarations, these will allow the compiler to recognize that class, without its' complete definition being available.

In the case of my code, the fix was adding forward declarations in the class files of MostPlayedListNode, SongPlaysNode and ArtistPlaysNode.

for example, the top portion of the updated MostPlayedListNode.h file:

using std::shared_ptr;
using std::make_shared;

class ArtistPlaysNode; // this is a forward declaration
class SongPlaysNode; // this is a forward declaration

class MostPlayedListNode {
private:
    int numberOfPlays;
    shared_ptr<ArtistPlaysNode> artistPlaysTree;
    shared_ptr<ArtistPlaysNode> ptrToLowestArtistId;
    shared_ptr<SongPlaysNode> ptrToLowestSongId;
    shared_ptr<MostPlayedListNode> previous;
    shared_ptr<MostPlayedListNode> next;

public:

And the updated ArtistPlayesNode.h file:

using std::shared_ptr;
using std::make_shared;

class SongPlaysNode; // this is a forward declaration
class MostPlayedListNode; // this is a forward declaration

class ArtistPlaysNode : public TreeNode {
private:
    int artistId;
    shared_ptr<SongPlaysNode> SongPlaysTree;
    shared_ptr<MostPlayedListNode> ptrToListNode;
public:

In conclusion, while writing certain data structures, forward-declarations are important in order for the compiler to recognize all of the necessary objects, if they're not already defined when they are needed by the object referencing them. In my code I needed forward-declarations to account for Mutual Recursion, but that might not always be the case.

Mor Paz
  • 2,088
  • 2
  • 20
  • 38