0

I am working on a small project with three classes. But my code won't compile. These classes are PacketObject2, PacketList2 and PacketInt2.

The code won't compile with the error 'PacketObject2': base class undefined in both PacketInt2.h and PacketList2.h.

PacketObject2.h:

#pragma once
#include <iostream>

#include "PacketList2.h";

using namespace std;

class PacketObject2
{
public:
    virtual void Print();

    virtual int CompareTo(PacketObject2 other);

    virtual PacketList2 ToList();

    virtual bool IsOpen();

    virtual void AddInt(int value);

    virtual void OpenChild();

    virtual void CloseChild();

};

PacketObject does not have a cpp-file.

PacketList2.h:

#pragma once
#include "PacketObject2.h"
#include "PacketInt2.h"

#include <vector>
#include <iostream>

using namespace std;

class PacketList2 : public PacketObject2
{
private:
    vector<PacketObject2> objectsInList;
    bool isOpen;
public:

    PacketList2();
    PacketList2(PacketInt2 pi);

    PacketList2 ToList();

    void Print();

    int CompareTo(PacketObject2 other);

    void AddInt(int value);

    bool IsOpen();

    bool HasOpenChild();

    void OpenChild();

    void CloseChild();
};

PacketList2.cpp:

#include "PacketList2.h"
#include "PacketObject2.h"
#include "PacketInt2.h"


vector<PacketObject2> objectsInList;
bool isOpen = true;

PacketList2::PacketList2() {

}
PacketList2::PacketList2(PacketInt2 pi) {
    objectsInList.push_back(pi);
}

PacketList2 PacketList2::ToList() {
        return *this;
    }

void PacketList2::Print() {
    cout << '[';
    for (int i = 0; i < objectsInList.size(); i++) {
        objectsInList[i].Print();
        cout << ',';
    }
}

int PacketList2::CompareTo(PacketObject2 other) {
    PacketList2 otherList = other.ToList();
    for (int i = 0;
        i < min(objectsInList.size(), otherList.objectsInList.size());
        i++) {
        int comparison = objectsInList[i].CompareTo(otherList.objectsInList[i]);
        if (comparison != 0) {
            return comparison;
        }
    }
    return 0;
}

void PacketList2::AddInt(int value) {
    if (objectsInList.back().IsOpen()) {
        objectsInList.back().AddInt(value);
    }
    else {
        PacketInt2 pi(value);
        objectsInList.push_back(pi);
    }
}

bool PacketList2::IsOpen() {
    return isOpen;
}

bool PacketList2::HasOpenChild() {
    return objectsInList.back().IsOpen();
}

void PacketList2::OpenChild() {
    if (HasOpenChild()) {
        objectsInList.back().OpenChild();
    }
    else {
        PacketList2 pl;
        objectsInList.push_back(pl);
    }
}

void PacketList2::CloseChild() {
    if (HasOpenChild()) {
        objectsInList.back().CloseChild();
    }
    else {
        isOpen = false;
    }
}

PacketInt2.h:

#pragma once
#include "PacketList2.h"
#include "PacketObject2.h"

using namespace std;

class PacketInt2 : public PacketObject2
{
private:
    int value;
public:
    PacketInt2(int value);

    void Print();

    PacketList2 ToList();

    int CompareTo(PacketObject2 other);
};

PacketInt2.cpp:

#include "PacketInt2.h"
#include "PacketList2.h"

int value;

PacketInt2::PacketInt2(int value) {
    this->value = value;
}

void PacketInt2::Print() {
    cout << value;
}

PacketList2 PacketInt2::ToList() {
    PacketList2 pl(*this);
    return pl;
}

int PacketInt2::CompareTo(PacketObject2 other) {
    PacketInt2* otherPtr = dynamic_cast<PacketInt2*>(&other);
    if (otherPtr == nullptr) {
        return ToList().CompareTo(other);
    }
    if (otherPtr->value == value) {
        return 0;
    }
    if (value < otherPtr->value) {
        return 1;
    }
    if (value > otherPtr->value) {
        return -1;
    }
}

I think I have done something with the imports that doesn't work. I am very new to the concept of h-files. Can you guys help me understand what is wrong?

ojaoweir
  • 45
  • 1
  • 4
  • 1
    You're cross-including the two headers. Pick an order. – lorro Jan 04 '23 at 15:15
  • 1
    The error mentions the base class, which occurs well before the method declarations. This should be a clue that you could probably greatly simplify your [mre] for this question. It suggests that details after specifying the base class might be droppable. Try dropping the class methods, simplifying the definition of `PacketList2` to just `class PacketList2 : public PacketObject2 {};`. Then compile to make sure the issue is still reproduced. Then repeat for `PacketInt2`. – JaMiT Jan 04 '23 at 15:29
  • 1
    `PacketList2.h` includes `PacketObject2.h` which in turn includes `PacketList2.h`. Think very carefully what will happen when the compiler reads those header files (especially in light of `#pragma once`). The error should make sense then, The solution is not to have two header files including each other. Use forward declarations and/or out-of-class method definitions to break the cycle. – john Jan 04 '23 at 15:29
  • 1
    See [Resolve build errors due to circular dependency amongst classes](https://stackoverflow.com/questions/625799/) (possibly not a duplicate because it does not use a base class, but the principles are similar). – JaMiT Jan 04 '23 at 15:36
  • 1
    Please ask yourself why `PacketObject2.h` includes `PacketList2.h` and not the other way around. – Spencer Jan 04 '23 at 15:37

1 Answers1

2

Rewrite like this

#pragma once
#include <iostream>

class PacketList2; // forward declaration

class PacketObject2
{
public:
    virtual void Print();
    virtual int CompareTo(PacketObject2 other);
    virtual PacketList2 ToList();
    virtual bool IsOpen();
    virtual void AddInt(int value);
    virtual void OpenChild();
    virtual void CloseChild();

};

The forward declaration of PacketList2 allows you to remove the inclusion of "PacketList2.h" which breaks the cycle of header file includes.

I've also removed using namespace std; which is bad practice at the best of times but a sackable offense when placed in a header file.

Also, not what you asked about, but this is wrong

int PacketInt2::CompareTo(PacketObject2 other) {
    PacketInt2* otherPtr = dynamic_cast<PacketInt2*>(&other);

Should perhaps be this

int PacketInt2::CompareTo(PacketObject* other) {
    PacketInt2* otherPtr = dynamic_cast<PacketInt2*>(other);

or maybe this

int PacketInt2::CompareTo(const PacketObject& other) const {
    const PacketInt2* otherPtr = dynamic_cast<const PacketInt2*>(&other);

In your version other has lost it's polymorphic nature so the dynamic_cast is guaranteed to fail. In C++ polymorphism only works on pointers and references (like both of my suggestions). This issue is known as object slicing which you might want to research.

I'm getting former Java programmer vibes.

john
  • 85,011
  • 4
  • 57
  • 81