test.cpp:9:12: error: field ‘m_spouse’ has incomplete type ‘Person’
9 | Person m_spouse;
| ^~~~~~~~
test.cpp:5:7: note: definition of ‘class Person’ is not complete until the closing brace
5 | class Person {
| ^~~~~~
Until we have finished defining Person, it is not OK to use Person to name a variable. Even if this was allowed, we would have problems trying to construct a Person. To construct a Person, you would have to set up memory for their m_spouse, which is a Person. That Person object would need to allocate some space for its m_spouse, which in turn would need memory for another m_spouse, and so on forever.
This is not a problem if we use aggregation instead of composition. In the aggregation version of this code, we are not trying to store a Person inside of a Person. We are simply storing a memory address inside each Person. So this code will compile and run just fine:
The print() function checks to see if there is a spouse (remember that if (m_spouse) will be false if the spouse is a nullptr) to determine what to print. Only if there is a spouse do we use -> to access the name of that spouse.
The marry(Person* spouse) function takes the address of a Person object. It first sets the current object’s spouse to be that address. It then sets the spouse’s spouse spouse->m_spouse to be the current object’s address (this). Thus when we say anna.marry(&brian);, the anna object first stores the brian object’s address. It then sets the brian object’s m_spouse to be anna.
When the anna.marry(&brian) function is called, the memory for the call stack looks like the diagram below. The Anna and Brian objects in main still do not have spouses set. In the marry function, the this pointer has anna’s address, while the spouse parameter holds brian’s address:
The first line of the marry function - m_spouse = spouse; - changes anna’s m_spouse to be 0x6f0. So Anna’s spouse now points at the Brian object. The second line - spouse->m_spouse = this; - starts from spouse, follows the pointer (->) to access m_spouse. Thus it reaches the brian object’s m_spouse. It sets that to the value of this, which is 0x400. So Brian’s spouse is now Anna.
Examine Figure 18.12.3. Assume that the statements below were executed in main after marry() has executed (and assume all Persons variables are public and we can access them from main.) Match each statement with its output.
Construct a Person function getDivorce(). If the Person executing the function has a spouse, it should clear the spouse variable of both the spouse and current Person by setting them to nullptr. You will not need all of the blocks.