Objects that point to each other :( (FIXED)

I would really like to have two classes where an instance of class A has a pointer to an instance of class B and class B has a pointer to an instance of class A. I must be suffering brain fade because I keep getting compiler errors. Ideally I would have all the code in a .h but I’ve tried putting the classes into .cpp with .h files but still with no success.

I have shrunk the problem to the following in test9.ino

class A {
  public:
  B *b;
  void T(void){
    b->T();
  }
};

class B {
  public:
  A *a;
  void T(void){
    a->T();
  }
};

void setup() { //FN
}

void loop() { //FN
}

and the compiler returns

test9:9:3: error: 'B' does not name a type

   B *b;

   ^

C:\_ACB\Arduino\libraries\__ESM4\Projects\test9\test9.ino: In member function 'void A::T()':

test9:11:5: error: 'b' was not declared in this scope

     b->T();

     ^

exit status 1
'B' does not name a type

Please can someone help me out
TIA Alan)

Depends what you try to DO with those pointers. You can do the following:

In classA.h:

class B;

class A
{
  class B *pMyB = NULL;

  // Define claasA here
};

In classB.h:

class A;

class B
{
  class A *pMyA = NULL;

  // Define claasB here
};

But, your .h files CANNOT contain ANY references to member data or functions of the other class. They can only know the other class IS a class, and its name. Obviously, classA.cpp must #include classB.h, and vice-versa, so the .cpp files CAN know all the details of the two classes.

In case you care WHY this works...

When compiling the .h file, the compiler needs to know the size and type of all variables, including those pointers to classA and classB. When you declare a pointer to an object in a .h file, that is ALL it needs to know. But when you de-reference (i.e. - actually USE) that pointer, THEN the compiller needs to know ALL the details of the object, so it knows what data are available, and their types, and what functions are available, and their arguments and return types. The "class A;" and "class B;" are effectively prototypes, which tell the compiler that classA and classB exist (though they may be defined elsewhere), that they ARE classes, and their names. So, when the pointers are declared, the compiler knows the size of the pointers, and the names of the classes they point to - all it needs to know at that point.

When the .cpp files are compiled, after the compiler has parsed both #included .h files, it knows everything about both classes, so the code in the .cpp files can now use those pointers to access all the class data and functions.

So how would I code it?

By the way I do realise in my example calling one function from the other class would call the function from the first... and eventually go round and round ... until it shot up its own bottom - so to speak. It's just an example to show the problem - the real code is obviously rather different.

Ray, just noticed you made two postings. I only saw the second one as a notification on my phone. I see you have posted before on how to get around the problem. I'll investigate tomorrow when my brain has rested. Thank you.

The fact an object of class A points to an object of class B and vice-versa doesn't imply
any cycles in the graph, it just allows for it.

Normally you'd build a parse tree this way, and although the types are recursive,
the objects aren't.

Objects that point to each other (cyclic graph) is usually done with a setter-method to
close the loop. And yes recursive methods over cyclic graphs will blow the stack
(or if tail-call-optimized may simply hang forever).

Sorted :slight_smile:

For those who want a prescription on how to do this here is a minimal code example.

#include "Object2Object.h"

// This is Object2Object.ino


// one instance of A called a
A a;

// one instance of B called b
B b;

void setup() { //FN
  Serial.begin(1000000);
  
  Serial.println("assign address of b instance to the a instance");
  a.b = &b;

  Serial.println("invoke the y method of the b instance of a");  
  a.b->y();
  
  Serial.println("assign address of a instance to the b instance");
  b.a = &a;
  
  Serial.println("invoke the x method of the a instance of b");
  b.a->x();
}

void loop() { //FN
}
// This is Object2Object.h

class B;

class A {
  public:
  // instances of A have a pointer to an instance of B
  B *b;
  void x(void);
};

class B {
  public:
  // instances of B have a pointer to an instance of A
  A *a;
  void y(void);
};
#include "Arduino.h"
#include "Object2Object.h"

// This is Object2Object.cpp

void A::x(void){
  Serial.println("a's x method");
  // now invoke the b instances x method
  b->y();
}
  
void B::y(void){
  Serial.println("b's y method");
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.