0

Right now I have a base class, class Base{}, with two classes deriving from it, BFS{} and DFS{}. BFS has queue, and DFS has stack, so they both have a member called "nodes", but the type is their respective std::queue and std::stack. My search function takes in a pointer to base class as its parameter so that it can accept both derived classes, and runs the search by pushing and popping from the member classes inside the derived classes (as per the usual DFS BFS algorithms). The issue is, since I passed in my base class as the parameter, whenever I try to call push or pop on the member stack/queue called "nodes" from the derived classes, it always says that the push/pop cannot be done because there is no member inside the base class called "nodes". How am I supposed to make this work? Also, this setup is a requirement of the assignment I am doing and I just can't figure out how this is supposed to work, any help is appreciated. Thanks!

class Base {
public:
    virtual void push(uint64_t roomID, float intensity, int distance) = 0;
    virtual Node pop(void) = 0;
    virtual int size(void) = 0;
};

class Breadth : public Base {
public:
    std::queue<std::pair<uint64_t, int>> U;
    void push(uint64_t roomID, float intensity, int distance) { std::pair<uint64_t, int> p(roomID, distance); U.push(p); }
    Node pop() { Node rr; rr.ID = U.front().first; rr.distance = U.front().second;  U.pop(); return rr; }
    int size() { return U.size(); }
};

class Depth : public Base {
public:
    std::stack<std::pair<uint64_t, int>> U;
    void push(uint64_t roomID, float intensity, int distance) { std::pair<uint64_t, int> p(roomID, distance); U.push(p); }
    UnexploredRoom pop() { U.pop(); }
    int size() { U.size(); }
};

void robotSearch::searchLoop(Base* search, Discovered* D, uint64_t roomID)
{
    Node room;
    room.ID = roomID;
    room.distance = 0;
    search->U.push(room); //problem here, compiler wont let me push U
    ...
}
Royce Yu
  • 1
  • 1
  • 1
    Would be helpful if you linked a [MCVE](https://stackoverflow.com/help/minimal-reproducible-example) of what you're trying to do. – Ayjay Oct 16 '19 at 03:45

2 Answers2

2

To implement custom behaviour through a pointer to a base class, you need to use virtual functions. Another approach would be to use generic code with templates.

Example:

class Base {
public:
    virtual ~Base() {}
    virtual void push(int i) = 0;
    virtual int pop() = 0;
};

class DFS : public Base{
public:
    virtual void push(int i) override { /*...*/ }
    virtual int pop() override { /*...*/ return {}; }
};

class BFS : public Base {
public:
    virtual void push(int i) override { /*...*/ }
    virtual int pop() override { /*...*/ return {}; }
};
Ayjay
  • 3,413
  • 15
  • 20
  • Yup, I've already got the virtual functions. Everything is the same as what you've got, except for my BFS and DFS classes, there is an extra member for each of them. For BFS it is std::queue nodes and for DFS it is std::stack nodes. However, when I try to push to the queue or stack using the Base class pointer, it doesn't work and I don't know how to make it push to the member of the derived classes instead of the base class. – Royce Yu Oct 16 '19 at 04:05
  • Until you provide a [MCVE](https://stackoverflow.com/help/minimal-reproducible-example) I not really going to be able to help you. I sat down and wrote out some code and linked it, the least you could do is the same. – Ayjay Oct 16 '19 at 06:29
  • Added mcve, was a bit hesitant to put hw code onto the net. the "nodes" stack and queue is U here – Royce Yu Oct 16 '19 at 10:47
1

Right now, you have some virtual methods push and pop, but for some reason, you don't use them and instead try to access a member of the derived classes instead. You seem to have copied code from the answer by Ayjay but not applied it correctly.
That member U should really not be exposed like this, that is, it should be private, and you should use your class methods to manipulate it.

Therefore, you wouldn't write

search->U.push(room);

even if it was legal here (which it isn't, as the base class does not have anything named like that).
Instead, you go with

search->push(room);

Note that I omitted the other arguments that this takes, of course you also have to provide values for your intensity and distance arguments.

Doing so will call the appropriate method, that is either Breadth::push or Depth::push, which then will access the corresponding member of the respective class.

By the way, for reasons of control, you should use the override keyword as Ayjay did, and also, you should give a member a more descriptive name that U.

Aziuth
  • 3,652
  • 3
  • 18
  • 36
  • I see now, thanks! (actually I didn't copy the code from Ayjay, it was the original code on my hw that I couldnt get to work) – Royce Yu Oct 16 '19 at 12:41