It's often convenient to think of association as double-ended aggregation. While this conceptualization may not always work, it's a helpful starting point. Like aggregation, association has a weak or loose binding implemented with pointers. Consequently, the program is not required to build the relationship with the constructors as it is in the case of composition. The program can create and break the association relationship binding the related objects whenever convenient. Programmers may choose to build the relationship with setter or constructor functions as best fits the problem.
Setter functions allow programmers to establish or update the pointer variables implementing the association relationship. The program can create the associated objects on the stack or the heap. One of association's major challenges - one of the characteristics making it more difficult than aggregation to implement - is the necessity of changing both pointers when updating the relationship. Failing to change one pointer will result in incoherency and break the relationship's bidirectionality.
project.h | contractor.h |
---|---|
class contractor; // forward declaration class project { private: contractor* theContractor; public: void set_contractor(contractor* a_c) { theContractor = a_c; } }; |
class project; // forward declaration class contractor; { private: project* theProject; public: void set_project(project* a_p) { theProject = a_p; } }; |
client1.cpp (stack objects) | client2.cpp (heap objects) |
#include "contractor.h" #include "project.h" int main() { project big; contractor fred; . . . . set_contractor(&fred); set_project(&big); . . . . return 0; } |
#include "contractor.h" #include "project.h" int main() { project* big = new project; contractor* fred = new contractor; . . . . set_contractor(fred); set_project(big); . . . . return 0; } |
While programmers are not required to build association relationships with constructors, they may. Furthermore, while programmers can break or change an association relationship whenever convenient, the relationship may persist from its creation to program termination.
project.h | contractor.h |
---|---|
#pragma once #include <iostream> using namespace std; class contractor; // forward dec #include "contractor.h" class project { private: contractor* theContractor; public: project(); // Pair a project(contractor* a_c); // Pair b }; |
#pragma once #include <iostream> using namespace std; class project; // forward dec #include "project.h" class contractor { private: project* theProject; public: contractor(project* a_p); // Pair a contractor(); // Pair b }; |
project.cpp | contractor.cpp |
#include "project.h" project::project() // pair a { theContractor = new contractor(this); } project::project(contractor* a_c) // pair b { theContractor = a_c; } |
#include "contractor.h" contractor::contractor(project* a_p) // pair a { theProject = a_p; } contractor::contractor() // pair b { theProject = new project(this); } |
client.cpp | |
#include "contractor.h" #include "project.h" int main() { // Pair a project little; // stack project* big = new project(); // heap . . . . return 0; } |
#include "contractor.h" #include "project.h" int main() { // Pair b contractor foo; // stack contractor* bar = new contractor(); // heap . . . . return 0; } |