ISR's and classes

As you might noticed at some point, you can instantiate as many classes as you want, but you can only have one ISR of the same type.
The reason is, a class is a construct to basically abstract your code, as ISR's are very close to the hardware in use.

There are ways though. I'll show some possibilities below.

By calling a class method (my preferred method)

One way is to keep the ISR in the main code and call a dedicated class method within the ISR. With this you can still instantiate many classes and you keep control of the ISR. It might be slightly slower because of the context switch and you need not forget to add the functionality in the main code.

The class called by the isr can inline to make it faster.

some_class.hpp:

class SOME_CLASS {
  public:
    SOME_CLASS();
    void some_functions();
    void isr();

  inline void SOME_CLASS::isr() {
    // do some stuff
    // it's inline to potentially make the context switch faster, but depends on the compiler
    // the compiler might create a copy of the code instead of a reference in the ISR
  }
}

main.cpp:

#include "some_class.hpp"

SOME_CLASS instance1;
SOME_CLASS instance2;

ISR(SOME_ISR) {
  instance1.isr();
  instance2.isr();
}

int main() {
  // do some stuff
}

By keeping a reference of the class instance

Another way is to keep a static reference of the class. You won't be able to instantiate the class multiple times though, but you can "hide" your ISR in the class.

some_class.hpp:

class SOME_CLASS {
  public:
    SOME_CLASS();
    void some_functions();

    static SOME_CLASS *class_ptr;

  private:
    uint8_t is_running;
}

some_class.cpp:

#include "some_class.hpp"
SOME_CLASS *SOME_CLASS::class_ptr;

SOME_CLASS:SOME_CLASS() {
  this->class_ptr = this;
}

ISR(SOME_ISR) {
  // access class property
  SOME_CLASS::class_ptr->is_running = 1;
}

main.cpp:

#include "some_class.hpp"

SOME_CLASS instance;

int main() {
  // do some stuff
}