using a class with static methods

I’m writing a game and I need to compress my data.
so I’m writing a class to hold much of the information to sprites in a single unsigned long variable.
this class then packs and unpacks the data using bitwise information in static functions.

i’ve torn most of those functions out and kept only two basic ones for this example.
I don’t know how to call these functions and keep getting an error in my loop() trying to call

MotionData::Get_Loc(MD);
and
MotionData::Set_Loc(MotionData *MD);

I’m using pointers and I think that’s what’s messing me up.

here’s the code

class Point
{
  public:
    Point(short x, short y);
    short X;
    short Y;
};

Point::Point(short x, short y)
  :
  X(x),
  Y(y)
{
}
/*
   uses 32 bit unsigned long integer to store :
                bits 0-4          Map Current Location Y              (range from 0-51)
                bits 5-9          Map Current Location X              (range from 0-51)
                bits 10-14        Map Previous Location Y             (range from 0-51)
                bits 15-19        Map Previous Location X             (range from 0-51)
                bits 20, 21       Screen Current Location Y           (range from 0-3)
                bits 22, 23, 24   Screen Current Location X           (range from 0-7)
                bits 25, 26       Screen Previous Location Y          (range from 0-3)
                bits 27, 28, 29   Screen Previous Location X          (range from 0-7)
                bits 30, 31       direction of motion where 00 = Left, 01 = right, 10 = up & 11= down
*/
class MotionData
{
  public :
    MotionData();
    static Point Loc_Get(MotionData MD);
    static void Loc_Set(MotionData *MD, Point ptLocNew);
    unsigned long ulngData;
  
};


MotionData::MotionData() {}

static Point MotionData::Loc_Get(MotionData MD)
{
  unsigned short ushMask_KeepLoc = (B00000011) << 8 + (B11111111);
  unsigned short ushTemp = ((unsigned short)MD.ulngData) & ushMask_KeepLoc;

  unsigned short ushMask_KeepY = ((byte)0 << 8) + B00011111;
  short shY = ushTemp & ushMask_KeepY;
  ushTemp >> 8;
  short shX = (short)ushTemp;
  return Point(shX, shY);
};

static void MotionData::Loc_Set(MotionData *MD, Point ptLocNew)
{
  unsigned long ulngTemp = MD->ulngData;
  unsigned short ushTemp = (unsigned short)abs(ptLocNew.X);
  ushTemp << 5;
  ushTemp = ushTemp | (unsigned short)abs(ptLocNew.Y);

  unsigned short ushMask_EraseOldValue = ((B11111100) << 8) + (B00000000);
  ulngTemp = ulngTemp & ushMask_EraseOldValue;

  ulngTemp = ulngTemp | ushTemp;
  MD->ulngData = ulngTemp;
}


MotionData MD();

void setup()
{
  
}

int intX =0;
void loop()
{

  Point ptLoc =  MotionData::Loc_Get(*MD);  // ERROR
  intX = (intX +1 )%64;
  MotionData::Loc_Set(*MD, Point(intX, ptLoc.Y)); // ERROR
  
  delay(100);
}

A number of things wrong here.

  • Why does Loc_Get() use pass-by-value while Loc_Set() uses pass-by-pointer? For consistency, I'd make them both either pass-by-pointer or pass-by-reference. Since Loc_Get() doesn't change the value passed, use 'const MotionData *' or 'const MotionData &'.

  • This:

MotionData MD();

does not instantiate an a MotionData object called MD. It's the prototype for a function named MD that takes no arguments and returns an object of type MotionData. Use this instead:

MotionData MD;
  • Get rid of the 'static' keyword when you define Loc_Get and Loc_Set outside of the class declaration.

Clean that up, then re-post updated code with complete error messages to get help with the remaining problems --- which there will be as there's too much wrong to fix in one reply.

thank you for your reply,

I’ve taken both functions out of the class and made them non-static.
and compiled it alright.
so… that’s progress but I may as well not have a class at all and just save my data in an unsigned long.

keeping the functions in the class and making them non-static would reproduce every function in every instance of the class which defeats the purpose of making the class which was to reduce the amount of data.
I’d like to keep the functions in the class and make the fact that the data is an unsigned long invisible to the calling functions which expect and use Point objects.

here’s my code. it compiles.

class Point
{
  public:
    Point(short x, short y);
    short X;
    short Y;
};

Point::Point(short x, short y)
  :
  X(x),
  Y(y)
{
}
/*
   uses 32 bit unsigned long integer to store :
                bits 0-4          Map Current Location Y              (range from 0-51)
                bits 5-9          Map Current Location X              (range from 0-51)
                bits 10-14        Map Previous Location Y             (range from 0-51)
                bits 15-19        Map Previous Location X             (range from 0-51)
                bits 20, 21       Screen Current Location Y           (range from 0-3)
                bits 22, 23, 24   Screen Current Location X           (range from 0-7)
                bits 25, 26       Screen Previous Location Y          (range from 0-3)
                bits 27, 28, 29   Screen Previous Location X          (range from 0-7)
                bits 30, 31       direction of motion where 00 = Left, 01 = right, 10 = up & 11= down
*/
class MotionData
{
  public :
    MotionData();
    unsigned long ulngData;
  
};


MotionData::MotionData() {}

Point Loc_Get(MotionData *MD)
{
  unsigned short ushMask_KeepLoc = (B00000011) << 8 + (B11111111);
  unsigned short ushTemp = ((unsigned short)MD->ulngData) & ushMask_KeepLoc;

  unsigned short ushMask_KeepY = ((byte)0 << 8) + B00011111;
  short shY = ushTemp & ushMask_KeepY;
  ushTemp >> 8;
  short shX = (short)ushTemp;
  return Point(shX, shY);
};

void Loc_Set(MotionData *MD, Point ptLocNew)
{
  unsigned long ulngTemp = MD->ulngData;
  unsigned short ushTemp = (unsigned short)abs(ptLocNew.X);
  ushTemp << 5;
  ushTemp = ushTemp | (unsigned short)abs(ptLocNew.Y);

  unsigned short ushMask_EraseOldValue = ((B11111100) << 8) + (B00000000);
  ulngTemp = ulngTemp & ushMask_EraseOldValue;

  ulngTemp = ulngTemp | ushTemp;
  MD->ulngData = ulngTemp;
}


MotionData MD;

void setup()
{
  
}

int intX =0;
void loop()
{

  Point ptLoc =  Loc_Get(&MD);
  intX = (intX +1 )%64;
  Loc_Set(&MD, Point(intX, ptLoc.Y));
  
  delay(100);
}

I didn’t say make them non-static. I said “Get rid of the ‘static’ keyword when you define Loc_Get and Loc_Set outside of the class declaration.”:

class myClass {
  public:
    static void aStaticFunction();
};

void myClass::aStaticFunction() {  // <------------ No "static" keyword before "void"!!!!!!!!!
  // Do something
}

void setup() {
  myClass::aStaticFunction();
}

void loop() {
}

well alright then… :slight_smile:

this seems to be doing what I want it to…

class Point
{
  public:
    Point(short x, short y);
    short X;
    short Y;
};

Point::Point(short x, short y)
  :
  X(x),
  Y(y)
{
}
/*
   uses 32 bit unsigned long integer to store :
                bits 0-4          Map Current Location Y              (range from 0-51)
                bits 5-9          Map Current Location X              (range from 0-51)
                bits 10-14        Map Previous Location Y             (range from 0-51)
                bits 15-19        Map Previous Location X             (range from 0-51)
                bits 20, 21       Screen Current Location Y           (range from 0-3)
                bits 22, 23, 24   Screen Current Location X           (range from 0-7)
                bits 25, 26       Screen Previous Location Y          (range from 0-3)
                bits 27, 28, 29   Screen Previous Location X          (range from 0-7)
                bits 30, 31       direction of motion where 00 = Left, 01 = right, 10 = up & 11= down
*/
class MotionData
{
  public :
    MotionData();
    static void Loc_Set(MotionData *MD, Point ptLocNew);
    static Point Loc_Get(MotionData *MD);
    unsigned long ulngData;
  
};


MotionData::MotionData() {}

Point MotionData::Loc_Get(MotionData *MD)
{
  unsigned short ushMask_KeepLoc = (B00000011) << 8 + (B11111111);
  unsigned short ushTemp = ((unsigned short)MD->ulngData) & ushMask_KeepLoc;

  unsigned short ushMask_KeepY = ((byte)0 << 8) + B00011111;
  short shY = ushTemp & ushMask_KeepY;
  ushTemp >> 8;
  short shX = (short)ushTemp;
  return Point(shX, shY);
};

void MotionData::Loc_Set(MotionData *MD, Point ptLocNew)
{
  unsigned long ulngTemp = MD->ulngData;
  unsigned short ushTemp = (unsigned short)abs(ptLocNew.X);
  ushTemp << 5;
  ushTemp = ushTemp | (unsigned short)abs(ptLocNew.Y);

  unsigned short ushMask_EraseOldValue = ((B11111100) << 8) + (B00000000);
  ulngTemp = ulngTemp & ushMask_EraseOldValue;

  ulngTemp = ulngTemp | ushTemp;
  MD->ulngData = ulngTemp;
}


MotionData MD;

void setup()
{
  
}

int intX =0;
void loop()
{

  Point ptLoc =  MotionData::Loc_Get(&MD);
  intX = (intX +1 )%64;
  MotionData::Loc_Set(&MD, Point(intX, ptLoc.Y));
  
  delay(100);
}

thanks!

Christ_Kennedy:
thanks!

No problem. Like I mentioned, it would be better form to specify 'const' for the parameter to your Loc_Get() function. This is your promise to the compiler that you won't modify (since you don't need to) the data item pointed to by the pointer. Doing this helps the compiler look for errors.

In the class declaration:

static Point Loc_Get(const MotionData *MD);

In the function implementation:

Point MotionData::Loc_Get(const MotionData *MD) {

thanks,
But I don't understand why you want to make the input referenced object a constant since I want to use the static functions in order to modify (not constant) the contents of the unsigned long variable.

... and
it was late last night and I only compiled it without testing it when I said that it was working but actually the classObject being passed by reference is coming back unchanged.
I have Serial.print() statements in the Loc_Set() call and the ulngData variable is being modified there but when i print it in the calling loop() function it hasn't been changed... which is wrong.
why is the variable being sent by reference not being modified?

You want to make the arguments const where reasonable, so attempts to change them accidentally are caught. If you KNOW that a function is supposed to change an argument, then don't make it const.

gfvalvo didn't say to make every argument const - only the ones that should be const.

ok, thank you.
but I still don't know why the instance of MotionData being passed by reference is returning as if it had not been passed by reference.

am I using the pointers correctly, I suspect not.

Christ_Kennedy:
I have Serial.print() statements in the Loc_Set() call and the ulngData variable is being modified there but when i print it in the calling loop() function it hasn't been changed.

There are no such print() statements in the code you posted.
There are no results of the alleged print() statements in your post either.

but I still don't know why the instance of MotionData being passed by reference is returning as if it had not been passed by reference.

I don't see any proof of that assertion. My code would be littered with Serial.print() statements, and I'd be showing the output to prove that the code wasn't working. YMMV.

thank you all for your interest.

here is my updated (Forum version) code.

  class Point
  {
    public:
      Point(short x, short y);
      short X;
      short Y;
  };

  Point::Point(short x, short y)
    :
    X(x),
    Y(y)
  {
  }
  class MotionData
  {
    public :
      MotionData();
      static Point Loc_Get(const MotionData *MD);
      static void Loc_Set(MotionData *MD, Point ptLocNew);
      static Point LocPrev_Get(const MotionData *MD);

      static Point ScreenLoc_Get(const MotionData *MD);
      static Point ScreenLocPrev_Get(const MotionData *MD);

      static byte Dir_Get(const MotionData *MD);

      unsigned long ulngData = 0;
  };


  MotionData::MotionData() {}

  Point MotionData::Loc_Get(const MotionData *MD)
  {
    unsigned short ushMask_KeepLoc = (B00000011) << 8 + (B11111111);
    unsigned short ushTemp = ((unsigned short)MD->ulngData) & ushMask_KeepLoc;

    unsigned short ushMask_KeepY = ((byte)0 << 8) + B00011111;
    short shY = ushTemp & ushMask_KeepY;
    ushTemp >> 8;
    short shX = (short)ushTemp;
    return Point(shX, shY);
  };

  void MotionData::Loc_Set(MotionData *MD, Point ptLocNew)
  {
    Serial.print("  Loc_Set() --------------------- start ------------------");
    Serial.println(MD->ulngData);

    unsigned long ulngTemp = MD->ulngData;
    unsigned short ushTemp = (unsigned short)abs(ptLocNew.X);
    ushTemp << 5;
    ushTemp = ushTemp | (unsigned short)abs(ptLocNew.Y);

    unsigned short ushMask_EraseOldValue = ((B11111100) << 8) + (B00000000);
    ulngTemp = ulngTemp & ushMask_EraseOldValue;

    ulngTemp = ulngTemp | ushTemp;
    MD->ulngData = ulngTemp;
    Serial.print("  ulngTemp:");
    Serial.print(ulngTemp);
    Serial.print("  MD->ulngData:");
    Serial.println(MD->ulngData);
    Serial.println("  Loc_Set() --------------------------finish-----------------------");
  }

  Point MotionData::LocPrev_Get(const MotionData *MD)
  {
    unsigned short ushMask_KeepLoc = (B00000011) << 8 + (B11111111);
    unsigned short ushTemp = ((unsigned short)MD->ulngData >> 10) & ushMask_KeepLoc;

    unsigned short ushMask_KeepY = ((byte)0 << 8) + B00011111;
    short shY = ushTemp & ushMask_KeepY;
    ushTemp >> 8;
    short shX = (short)ushTemp;
    return Point(shX, shY);
  }

  


  Point MotionData::ScreenLoc_Get(const MotionData *MD)
  {
    unsigned long ulngMask_KeepScreenLoc = B00000001 << 24
                                           + B11110000 << 16
                                           + B00000000 << 8
                                           + B00000000;
    unsigned long ulngScreenLoc = MD->ulngData & ulngMask_KeepScreenLoc;
    unsigned short ushScreenLoc = ulngScreenLoc >> 20;

    unsigned short ushMaskKeepY = B00000000 << 8
                                  + B00000011;

    unsigned short ushY = ushScreenLoc & ushMaskKeepY;
    unsigned short ushX = ushScreenLoc >> 2;

    Point ptRetVal = Point(ushX, ushY);
    return ptRetVal;
  }

  
  Point MotionData::ScreenLocPrev_Get(const MotionData *MD)
  {
    unsigned short ushScreenLocCurrent = (unsigned short)
                                         ((MD->ulngData >> 25)
                                          & (B00000000 << 24
                                              + B00000000 << 16
                                              + B00000000 << 8
                                              + B00011111));
    unsigned short ushY = ushScreenLocCurrent
                          & (B00000000 << 8
                             + B00000011);
    ushScreenLocCurrent >> 2;
    unsigned short ushX = ushScreenLocCurrent;
    return Point(ushX, ushY);
  }

  

  byte MotionData::Dir_Get(const MotionData *MD)
  {
    unsigned long ulngDirMotion = MD->ulngData >> 30;
    byte bytRetVal = (byte)ulngDirMotion;
    return bytRetVal;
  }

  
  MotionData MD;


  void setup()
  {

    Serial.begin(9600);

  }

  bool ShiftBit(unsigned long *ulngData)
  {
    bool bolRetVal = *ulngData % 2;
    *ulngData >> 1;
    return bolRetVal;
  }

  String ShiftBit(unsigned long *lngData, int intNum)
  {
    String strRetVal = "";
    for (int intCounter = 0; intCounter < intNum; intCounter ++)
    {
      strRetVal = (ShiftBit(*lngData) ? "1" : "0") + strRetVal;
    }
    return strRetVal;
  }

  void SerialPrintMotionData(MotionData *MD)
  {
    byte bytDirMotion = MotionData::Dir_Get(MD);
    Point ptLoc = MotionData::Loc_Get(MD);
    Point ptLocPrev = MotionData::LocPrev_Get(MD);
    Point ptScreenLoc = MotionData::ScreenLoc_Get(MD);
    Point ptScreenLocPrev = MotionData::ScreenLocPrev_Get(MD);

    unsigned long ulngData = MD->ulngData;
    String strBits_LocY = ShiftBit(&ulngData, 5);
    String strBits_LocX = ShiftBit(&ulngData, 5);
    String strBits_LocPrevY = ShiftBit(&ulngData, 5);
    String strBits_LocPrevX = ShiftBit(&ulngData, 5);
    String strBits_ScreenLocY = ShiftBit(&ulngData, 2);
    String strBits_ScreenLocX = ShiftBit(&ulngData, 3 );
    String strBits_ScreenLocPrevY = ShiftBit(&ulngData, 2);
    String strBits_ScreenLocPrevX = ShiftBit(&ulngData, 3);
    String strBits_DirMotion = ShiftBit(&ulngData, 2);

    Serial.println("  SerialPrintMotionData  -------------------start --------------------------------");
    Serial.print("  MD->ulngData = ");
    Serial.println(MD->ulngData);
    Serial.print("  ");
    Serial.print(strBits_DirMotion);
    Serial.print(" ");
    Serial.print(strBits_ScreenLocPrevX);
    Serial.print(" ");
    Serial.print(strBits_ScreenLocPrevY);
    Serial.print(" ");
    Serial.print(strBits_ScreenLocX);
    Serial.print(" ");
    Serial.print(strBits_ScreenLocY);
    Serial.print(" ");
    Serial.print(strBits_LocPrevX);
    Serial.print(" ");
    Serial.print(strBits_LocPrevY);
    Serial.print(" ");
    Serial.print(strBits_LocX);
    Serial.print(" ");
    Serial.println(strBits_LocY);

    Serial.print("  Dir Motion:");
    Serial.print(strBits_DirMotion);
    Serial.print(" = ");
    Serial.println(bytDirMotion);

    Serial.print("  ScreenLocPrevious ");
    Serial.print(strBits_ScreenLocPrevX);
    Serial.print(" ");
    Serial.print(strBits_ScreenLocPrevY);
    Serial.print("=(");
    Serial.print(ptScreenLocPrev.X);
    Serial.print(", ");
    Serial.print(ptScreenLocPrev.Y);
    Serial.println(")");

    Serial.print("  ScreenLoc ");
    Serial.print(strBits_ScreenLocX);
    Serial.print(" ");
    Serial.print(strBits_ScreenLocY);
    Serial.print("=(");
    Serial.print(ptScreenLoc.X);
    Serial.print(", ");
    Serial.print(ptScreenLoc.Y);
    Serial.println(")");

    Serial.print("  LocPrevious ");
    Serial.print(strBits_LocPrevX);
    Serial.print(" ");
    Serial.print(strBits_LocPrevY);
    Serial.print("=(");
    Serial.print(ptLocPrev.X);
    Serial.print(", ");
    Serial.print(ptLocPrev.Y);
    Serial.println(")");

    Serial.print("  Loc ");
    Serial.print(strBits_LocX);
    Serial.print(" ");
    Serial.print(strBits_LocY);
    Serial.print("=(");
    Serial.print(ptLoc.X);
    Serial.print(", ");
    Serial.print(ptLoc.Y);
    Serial.println(")");
    Serial.println("  SerialPrintMotionData  -------------------finish --------------------------------");
  }

  void loop()
  {
    Serial.println("loop() -------------------start-----------------");
    Point ptLoc =  MotionData::Loc_Get(&MD);
    Serial.print("ptLoc.X = ");
    Serial.println(ptLoc.X);

    ptLoc.X = (ptLoc.X + 1) % 52;

    MotionData::Loc_Set(&MD, ptLoc);

    SerialPrintMotionData(&MD);
    
    Serial.print("ptLoc.X = ");
    Serial.println(ptLoc.X);
    Serial.println("loop() -------------------finish -----------------");

    delay(100);
  }

to look at my data I have ShiftBit(*unsigned long, int) function that returns a string of numBits of 1’s & 0’s describing the content of the LSBits of that unsigned long so that I can see the unsigned long integer in terms of bits. and that doesn’t seem to be working either.
you can see that the ptLoc.X value returns from the Loc_Set() call affected but then when the loop() starts again Loc_Get() returns the original value of zero. so something’s not working.

I just noticed the logic in Loc_Get() right-shifts the masked XY values by 8 instead of 5.
it should read

ushTemp >> 5;

not

ushTemp >> 8;

but just getting the BitShift() debugging function working would be a giant leap forward.

By the way, this statement is absolutely untrue:

Christ_Kennedy:
keeping the functions in the class and making them non-static would reproduce every function in every instance of the class

There's only one copy of a class's instance (aka non-static) functions. It is called with a (implicit, hidden) pointer to the particular instance that identifies the data to operate on.

So, in the spirit of OOP encapsulation, I'd recommend dumping the idea of using static functions for this application as the functions you're trying to implement clearly operate on data that's unique to each instance.

That will get rid of the need to explicitly pass pointers.

Also, your basic pointer manipulation techniques seem OK. So, I'd guess that any problems you're having are due to the complex data gyrations you're performing in your quest for compaction. That's outside the scope of this thread as defined by its "Subject".

here is my updated (Forum version) code.

But, no output, so we can't see what it's doing.

thank you all for you generous help.

my data gyrations are working great.
I have the pointers figured out and am now using two functions that

  1. set bits in the unsigned long using bitStart, bitEnd and bytData to affect the content of an unsigned long passed by reference!
  2. getByte uses bitStart & bitEnd (assumes they are less then 8 bits apart) and returns a byte

they work by evaluating LSBit and right-shifting-out the source data as they left-shift-in the LSBit of the original unsigned long or the input data (depending on the bit being shifted)

all works great. thank you for your help

I had things to do today but finally got back to it an hour ago.

I have it working … and I think, despite all the data gyrations I’m doing, that its now an important tool in my arsenal.
lookst setBits() and getByte() functions as they do all the work. All my other functions (only two in example here) resort to them to get things done. I may rewrite getByte() to do it without reverseByte().
notice the line in setBits()

ulngRetVal = ulngRetVal + ((unsigned long)1 << 31);

where it shifts in a high bit from the left. the (unsigned long) is applied to the numeral 1 before it is shifted. otherwise it assumes the numeral 1 is a regular int (16 bits) and shifting it to the left 32 times obliviates it from existence. that was a minor stumbling block.

class Point
{
  public:
    Point(byte x, byte y);
    byte X = B00000000;
    byte Y = B00000000;
};

Point::Point(byte x, byte y)
  :
  X(x),
  Y(y)
{
}

class MotionData
{
  public :
    MotionData();
    static Point Loc_Get(const MotionData *MD);
    static void Loc_Set(MotionData *MD, Point ptLocNew);

    unsigned long ulngData = 0;

  private:
    static byte getByte(const MotionData *MD, byte bytBitStart, byte bytBitEnd);
    static void setBits(MotionData *MD, byte bytBitStart, byte bytBitEnd, byte bytDataIn);
    static unsigned long reverseULong(unsigned long ulngIn);
    static byte reverseByte(byte bytIn);
};

bool ShiftBit(unsigned long *ulngData)
{
  bool bolRetVal = (*ulngData % 2 == 1);
  *ulngData = *ulngData >> 1;
  return bolRetVal;
}


String ShiftBit(unsigned long *ulngData, int intNum)
{
  return ShiftBit(ulngData, intNum, false);
}

String ShiftBit(unsigned long *ulngData, int intNum, bool bolSpaceHex)
{
  String strRetVal = "";
  for (int intCounter = 0; intCounter < intNum; intCounter ++)
  {
    if (bolSpaceHex && intCounter % 4 == 0)
      strRetVal = " " + strRetVal;
    strRetVal = (ShiftBit(ulngData) ? "1" : "0") + strRetVal;
  }
  return strRetVal;
}


MotionData::MotionData() {}

byte MotionData::reverseByte(byte bytIn)
{
  byte bytRetVal = 0;
  for (byte bytCounter = 0; bytCounter < 8; bytCounter ++)
  {
    bytRetVal = bytRetVal + bytIn % 2;
    if (bytCounter < 7)
      bytRetVal = bytRetVal << 1;
    bytIn = bytIn >> 1;
  }
  return bytRetVal;
}

unsigned long MotionData::reverseULong(unsigned long ulngIn)
{
  unsigned long ulngRetVal = 0;

  for (byte bytCounter = 0; bytCounter < 32; bytCounter ++)
  {
    ulngRetVal = ulngRetVal + ulngIn % 2;
    if (bytCounter < 31)
      ulngRetVal = ulngRetVal << 1;
    ulngIn = ulngIn >> 1;
  }
  return ulngRetVal;
}

byte MotionData::getByte(const MotionData *MD, byte bytBitStart, byte bytBitEnd)
{
  unsigned long ulngTemp = MD->ulngData;

  byte bytTemp = 0;
  for (byte bytCounter = 0; bytCounter < 32; bytCounter ++)
  {
    if (bytCounter >= bytBitStart && bytCounter <= bytBitEnd)
    {
      bytTemp = bytTemp << 1;
      bytTemp = bytTemp + ulngTemp % 2;
    }
    ulngTemp =    ulngTemp >> 1;
  }
  bytTemp = MotionData::reverseByte(bytTemp);
  bytTemp = bytTemp >> (bytBitEnd - bytBitStart - 1);
  return bytTemp;
}

void MotionData::setBits(MotionData *MD, byte bytBitStart, byte bytBitEnd, byte bytDataIn)
{  
  //////////////////    COMMENT OUT NEXT LINE TO SEE setBits() WORKING
  /*
  Serial.println("setBits() ---------------start -----------------");
  Serial.print("bitStart:");
  Serial.print(bytBitStart);
  Serial.print("  bitEnd:");
  Serial.print(bytBitEnd);
  Serial.print("  bytDataIn:");
  Serial.println(String(bytDataIn,BIN));
  unsigned long ulngRetVal = MD->ulngData;

  for (short shCounter = 0; shCounter < 32; shCounter ++)
  {
    bool bolShiftIn = false;
    if (shCounter >= bytBitStart && shCounter <= bytBitEnd)
    {
      bolShiftIn = (bytDataIn % 2) == 1;
      bytDataIn = bytDataIn >> 1;
    }
    else
    {
      bolShiftIn = (ulngRetVal % 2) == 1;
    }

    ulngRetVal = ulngRetVal >> 1;
    
    Serial.println(".");
    Serial.print(shCounter);
    if (shCounter < 10)
      Serial.print(" ");
    Serial.print(".");

    if (bolShiftIn)
    {
      ulngRetVal = ulngRetVal + ((unsigned long)1 << 31);
      Serial.print("True");
    }
    else
      Serial.print("False");

    Serial.print(".");
    unsigned long ulngTemp = ulngRetVal;
    Serial.print(ShiftBit(&ulngTemp, 32));
  }

  MD->ulngData = ulngRetVal;
  Serial.println("setBits() ----------------finish-----------------");
  /*/
  unsigned long ulngRetVal = MD->ulngData;

  for (short shCounter = 0; shCounter < 32; shCounter ++)
  {
    bool bolShiftIn = false;
    if (shCounter >= bytBitStart && shCounter <= bytBitEnd)
    {
      bolShiftIn = (bytDataIn % 2) == 1;
      bytDataIn = bytDataIn >> 1;
    }
    else
    {
      bolShiftIn = (ulngRetVal % 2) == 1;
    }

    ulngRetVal = ulngRetVal >> 1;
  
    if (bolShiftIn)
      ulngRetVal = ulngRetVal + ((unsigned long)1 << 31);
  }

  MD->ulngData = ulngRetVal;
  // */
}

Point MotionData::Loc_Get(const MotionData *MD)
{
  byte bytX = MotionData::getByte(MD, 5, 9);
  byte bytY = MotionData::getByte(MD, 0, 4);
  return Point(bytX, bytY);
};

void MotionData::Loc_Set(MotionData *MD, Point ptLocNew)
{
  MotionData::setBits(MD, 5, 9, ptLocNew.X);
  MotionData::setBits(MD, 0, 4, ptLocNew.Y);
}


MotionData MD;



void setup()
{
  Serial.begin(9600);

}


void SerialPrintMotionData(MotionData *MD)
{
  Point ptLoc = MotionData::Loc_Get(MD);
  unsigned long ulngData = MD->ulngData;

  String strBits_LocY = ShiftBit(&ulngData, 5);
  String strBits_LocX = ShiftBit(&ulngData, 5);

  Serial.println("  SerialPrintMotionData  -------------------start --------------------------------");

  Serial.print("  Loc ");
  Serial.print(strBits_LocX);
  Serial.print(" ");
  Serial.print(strBits_LocY);
  Serial.print("=(");
  Serial.print(ptLoc.X);
  Serial.print(", ");
  Serial.print(ptLoc.Y);
  Serial.println(")");
  Serial.println("  SerialPrintMotionData  -------------------finish --------------------------------");
}

void loop()
{
  SerialPrintMotionData(&MD);

  Point ptLoc =  MotionData::Loc_Get(&MD);
  ptLoc.X = (ptLoc.X + 1) % 32;
  ptLoc.Y = (ptLoc.Y + 31) % 32;
  MotionData::Loc_Set(&MD, ptLoc);

  SerialPrintMotionData(&MD);

  delay(100);
}

As I pointed out, there is no advantage to defining those functions as static. If they all work with data of one instance at a time, you might as well make them instance functions and save yourself all the pointer passing.

having done nothing but C# for years now and getting back into C/C++ I need to get my feet wet with the pointers.
so, thanks for your opinion, but I found this class a great learning exercise.