2

This question gives answer only when the classes use each other as the member types, but not when they use the functions of each other. How to do it in the following example? Bar is a singleton container which handles the operations done on all Bars.

// Foo.h

#include "Bar.h"

class Foo {
public:
    Foo() { Bar::get_instance()->push_back(this); }

    void do_something() {}
};
// Bar.h

#include "Foo.h"
#include <vector>

class Bar {
public:
    Bar(const Bar &other) = delete;

    void operator=(const Bar &) = delete;

    static Bar *get_instance()
    {
        static Bar bar;
        return &bar;
    }

    void push_back(Foo *foo) { foos_.push_back(foo); }

    void do_something_all() { for (Foo *f : foos_) f->do_something(); }

private:
    Bar() = default;

    std::vector<Foo *> foos_;
};

2 Answers2

3

You split it up. Define the classes but put the implementation part after the class definition.

class Foo {
public:
    Foo(); // declare but do not implement

    // this can be implemented here since it doesn't need Bar:
    void do_something() { std::cout << "Foo::do_something()\n"; }
};

class Bar {
public:
    Bar(const Bar&) = delete;
    void operator=(const Bar&) = delete;

    static Bar& get_instance() { // return a reference instead
        static Bar bar;
        return bar;
    }

    // you can store a pointer - but require a reference:
    void push_back(Foo& foo) { foos_.push_back(&foo); }

    // or else you need to check for nullptr in here:
    void do_something_all() { for(Foo* f : foos_) f->do_something(); }

private:
    Bar() = default;

    std::vector<Foo*> foos_;
};

// Implementation part:
// Here Foo can use Bar

Foo::Foo() {
    Bar::get_instance().push_back(*this);
}

Demo

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
1

Forward declaration will do the trick, forward decalre in .h and include the header in cpp.

// Bar.h

//#include "Foo.h"
#include <vector>

class Foo; // <---- this one

class Bar {
public:
    Bar(const Bar &other) = delete;

    void operator=(const Bar &) = delete;

    static Bar *get_instance();

    // move definition in cpp
    void push_back(Foo *foo);

    // move definition in cpp
    void do_something_all();

private:
    Bar() = default;

    std::vector<Foo *> foos_;
};

// Bar.cpp

#include "Foo.h"

Bar* Bar::get_instance()
{
    static Bar bar;
    return &bar;
}

void Bar::push_back(Foo *foo) 
{ 
   foos_.push_back(foo); 
}
    
void Bar::do_something_all() 
{ 
   for (Foo *f : foos_) f->do_something();
}
Moia
  • 2,216
  • 1
  • 12
  • 34
  • I've tried to do this, this is exactly what's suggested in the answer I was referring to. But the compiler (or at least IDE) doesn't see the ```Foo```'s ```do_something()``` function. – i spin and then i lock Feb 11 '21 at 13:45
  • 2
    @kenticent move definition in .cpp. you can freely include bar.h there. – Moia Feb 11 '21 at 13:46