I am having trouble with RobotControl class members. The UML specifies the relation between RobotControl’s position and RangeSensor as composition. Doesn't using pointers for them, make them aggregation? How should I declare - create these members with respect to UML, or has UML mistaken?
Pointers in C++ can be used for both aggregation and composition. The distinction is, as correctly noted by Douglas, whether the lifetime of the objects is interconnected. In other words: Is the child destroyed when the parent is destroyed? The answer Yes stands for composition, No for aggregation.
Pointers in C++ can mean the ownership of another (dynamically created) object, or just refer to an object owned by someone else. Let’s show the differences in examples. I’ll explain why pointers can be useful for each type of relationship.
In this case, it is fine to only forward-declare the class Child
before class Parent
declaration and the child
member can be set and re-set during the lifetime of the Parent
.
class Child;
class Parent
{
public:
Parent(Child* ch) : child(ch) {}
Parent() : child(NULL) {}
void setChild(Child* ch) { child = ch; }
private:
Child* child;
};
The longest example shows that we can dynamically create and destroy the child
using a pointer. The child
’s lifetime is strongly interconnected with the Parent
. However, we can still swap child
ren during the lifetime of the Parent
thanks to pointers. This solution also allows to only forward-declare class Child
in the header file unlike the alternative below.
// --- header file
class Child;
class Parent
{
public:
Parent();
~Parent();
void renewChild();
private:
Child* child;
};
// --- source file
#include "child.h"
Parent::Parent()
: child(new Child)
{
}
Parent::~Parent()
{
delete child;
}
void Parent::renewChild()
{
delete child;
child = new Child;
}
This example is a subject to the Rule of three/five/zero. I am intentionally letting the implementation of missing recommended methods up to the user, keeping this answer dialect-agnostic and as simple as possible.
Instead of writing constructor and destructor manually, you can just declare child
in the class declaration and let the compiler to do the construction and destruction for you. This is valid as long as the class Child
’s constructor requires no parameters (otherwise you’d need to write class Parent
’s constructor manually) and the class Child
is fully declared before the declaration of class Parent
.
#include "child.h"
class Parent
{
private:
Child child;
};
To be complete, the alternative to using pointers for aggregation is using a reference. However, this prevents swapping child
ren during the lifetime of the Parent
object.
class Child;
class Parent
{
public:
Parent(Child& ch) : child(ch) {}
private:
Child& child;
};