Problem with using static method in interrupt

I'm trying to write a library for using a rotary encoder. My initial implementation didn't use an interrupt and was super flakey once inserted into complex code. After much reading I decided to rewrite using an interrupt. After more reading (a few post here: 47613, 160101 & 47613) I rewrote my library to use static methods and properties (RotaryEncoder).

.h file:

class RotaryEncoder {

		RotaryEncoder( byte clockPin , byte dataPin );

		 * (called by Interrupt Service Routine)
		 * captures changes made to the position of the rotary encoder
		 * via an interrupt. The changes can then be used by any of
		 * the getPostion public methods
		 * NOTE: even though this method is static as are all the
		 *		 properties used within it, you can still have
		 *		 multiple encoder objects on the same pins
		 * NOTE ALSO: at least for the moment, you can only have ONE
		 *		 encoder on the board.
		 *		 (Hopefully) This is only temporary
		 * (see for
		 *	why it's important to do this via a static method)
		static void ISR_UpdatePosition();

		 * returns the current (cumulative) position of the rotary
		 * encoder
		 * @param long startPosition the value that the rotary
		 *		  encoder is going to modify
		 * @param int increment the increment by which the
		 *		  position of the encoder is stepped with each move
		long getPosition(long startPosition, int increment = 1);

		 * starts or stops the encoder's interrupt method
		static void startStopListening();

		 * whether or not the interrupt is active and listening for
		 * changes in the rotery encoder
		static bool _active;

		static byte _clkPin;
		static byte _dtPin;

		volatile static int _previousClkValue;
		 * the internally stored position of the encoder relative to
		 * when getPosition() was last called.
		volatile static int _pos;

and .cpp

RotaryEncoder::RotaryEncoder( byte clockPin , byte dataPin ) {
	RotaryEncoder::_clkPin = clockPin;
	RotaryEncoder::_dtPin = dataPin;

	pinMode(RotaryEncoder::_clkPin, INPUT);
	pinMode(RotaryEncoder::_dtPin, INPUT);

void RotaryEncoder::ISR_UpdatePosition() {
	int clkValue = digitalRead(RotaryEncoder::_clkPin);

	if ((RotaryEncoder::_previousClkValue == LOW) && (clkValue == HIGH)) {
		if (digitalRead(RotaryEncoder::_dtPin) == LOW) {
			RotaryEncoder::_pos -= 1;
		} else {
			RotaryEncoder::_pos += 1;
//		Serial.print(RotaryEncoder::_pos);
//		Serial.println();
	RotaryEncoder::_previousClkValue = clkValue;

long RotaryEncoder::getPosition(long startPosition, int increment = 1) {
	startPosition *= (RotaryEncoder::_pos * increment);
	RotaryEncoder::_pos = 0;
	return startPosition;

void RotaryEncoder::startStopListening() {
	RotaryEncoder::_active = !RotaryEncoder::_active;

	RotaryEncoder::_previousClkValue = 0;
	RotaryEncoder::_pos = 0;

	if (RotaryEncoder::_active == true) {
		attachInterrupt(digitalPinToInterrupt(RotaryEncoder::_clkPin), RotaryEncoder::ISR_UpdatePosition, CHANGE);
	} else {

bool RotaryEncoder::_active = false;

Now I have a weird compile error that I don't understand:

C:\Users\evan\AppData\Local\Temp\ccnkZez3.ltrans0.ltrans.o: In function `RotaryEncoder::ISR_UpdatePosition()':
ccnkZez3.ltrans0.o:(.text+0x398): undefined reference to `RotaryEncoder::_clkPin'
ccnkZez3.ltrans0.o:(.text+0x3a2): undefined reference to `RotaryEncoder::_previousClkValue'
ccnkZez3.ltrans0.o:(.text+0x3a6): undefined reference to `RotaryEncoder::_previousClkValue'
ccnkZez3.ltrans0.o:(.text+0x3b4): undefined reference to `RotaryEncoder::_dtPin'
ccnkZez3.ltrans0.o:(.text+0x3c0): undefined reference to `RotaryEncoder::_pos'
ccnkZez3.ltrans0.o:(.text+0x3c4): undefined reference to `RotaryEncoder::_pos'
ccnkZez3.ltrans0.o:(.text+0x3cc): undefined reference to `RotaryEncoder::_pos'
ccnkZez3.ltrans0.o:(.text+0x3d0): undefined reference to `RotaryEncoder::_pos'
ccnkZez3.ltrans0.o:(.text+0x3d4): undefined reference to `RotaryEncoder::_previousClkValue'
ccnkZez3.ltrans0.o:(.text+0x3d8): undefined reference to `RotaryEncoder::_previousClkValue'
ccnkZez3.ltrans0.o:(.text+0x3e2): undefined reference to `RotaryEncoder::_pos'
ccnkZez3.ltrans0.o:(.text+0x3e6): undefined reference to `RotaryEncoder::_pos'
C:\Users\evan\AppData\Local\Temp\ccnkZez3.ltrans0.ltrans.o: In function `RotaryEncoder::getPosition(long, int)':
ccnkZez3.ltrans0.o:(.text+0x528): undefined reference to `RotaryEncoder::_pos'
ccnkZez3.ltrans0.o:(.text+0x52c): undefined reference to `RotaryEncoder::_pos'
ccnkZez3.ltrans0.o:(.text+0x530): undefined reference to `RotaryEncoder::_pos'
C:\Users\evan\AppData\Local\Temp\ccnkZez3.ltrans0.ltrans.o:ccnkZez3.ltrans0.o:(.text+0x534): more undefined references to `RotaryEncoder::_pos' follow
C:\Users\evan\AppData\Local\Temp\ccnkZez3.ltrans0.ltrans.o: In function `global constructors keyed to 65535_0_RotaryEncoder.cpp.o.1909':
ccnkZez3.ltrans0.o:(.text.startup+0x68): undefined reference to `RotaryEncoder::_clkPin'
ccnkZez3.ltrans0.o:(.text.startup+0x6e): undefined reference to `RotaryEncoder::_dtPin'
ccnkZez3.ltrans0.o:(.text.startup+0x78): undefined reference to `RotaryEncoder::_dtPin'
C:\Users\evan\AppData\Local\Temp\ccnkZez3.ltrans0.ltrans.o: In function `main':
ccnkZez3.ltrans0.o:(.text.startup+0x16c): undefined reference to `RotaryEncoder::_previousClkValue'
ccnkZez3.ltrans0.o:(.text.startup+0x170): undefined reference to `RotaryEncoder::_previousClkValue'
ccnkZez3.ltrans0.o:(.text.startup+0x174): undefined reference to `RotaryEncoder::_pos'
ccnkZez3.ltrans0.o:(.text.startup+0x178): undefined reference to `RotaryEncoder::_pos'
ccnkZez3.ltrans0.o:(.text.startup+0x17c): undefined reference to `RotaryEncoder::_clkPin'
collect2.exe: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino/Genuino Mega or Mega 2560.

There are three files involved in a library - a header file, a source file, and a sketch. You posted only two of the three.

Why do you think you need RotaryEncoder:: in front of all the static member names?

And I hope those are not the complete .h and .cpp files? I miss including the header in the source. I miss including Arduino.h in the header. And I miss guarding the header…