16.2 — Composition

Object composition

In real-life, complex objects are often built from smaller, simpler objects. For example, a car is built using a metal frame, an engine, some tires, a transmission, a steering wheel, and a large number of other parts. A personal computer is built from a CPU, a motherboard, some memory, etc… Even you are built from smaller parts: you have a head, a body, some legs, arms, and so on. This process of building complex objects from simpler ones is called object composition.

Broadly speaking, object composition models a “has-a” relationship between two objects. A car “has-a” transmission. Your computer “has-a” CPU. You “have-a” heart. The complex object is sometimes called the whole, or the parent. The simpler object is often called the part, child, or component.

In C++, you’ve already seen that structs and classes can have data members of various types (such as fundamental types or other classes). When we build classes with data members, we’re essentially constructing a complex object from simpler parts, which is object composition. For this reason, structs and classes are sometimes referred to as composite types.

Object Composition is useful in a C++ context because it allows us to create complex classes by combining simpler, more easily manageable parts. This reduces complexity, and allows us to write code faster and with less errors because we can reuse code that has already been written, tested, and verified as working.

Types of object composition

There are two basic subtypes of object composition: composition and aggregation. We’ll examine composition in this lesson, and aggregation in the next.

A note on terminology: the term “composition” is often used to refer to both composition and aggregation, not just to the composition subtype. In this tutorial, we’ll use the term “object composition” when we’re referring to both, and “composition” when we’re referring specifically to the composition subtype.


To qualify as a composition, an object and a part must have the following relationship:

  • The part (member) is part of the object (class)
  • The part (member) can only belong to one object (class) at a time
  • The part (member) has its existence managed by the object (class)
  • The part (member) does not know about the existence of the object (class)

A good real-life example of a composition is the relationship between a person’s body and a heart. Let’s examine these in more detail.

Composition relationships are part-whole relationships where the part must constitute part of the whole object. For example, a heart is a part of a person’s body. The part in a composition can only be part of one object at a time. A heart that is part of one person’s body can not be part of someone else’s body at the same time.

In a composition relationship, the object is responsible for the existence of the parts. Most often, this means the part is created when the object is created, and destroyed when the object is destroyed. But more broadly, it means the object manages the part’s lifetime in such a way that the user of the object does not need to get involved. For example, when a body is created, the heart is created too. When a person’s body is destroyed, their heart is destroyed too. Because of this, composition is sometimes called a “death relationship”.

And finally, the part doesn’t know about the existence of the whole. Your heart operates blissfully unaware that it is part of a larger structure. We call this a unidirectional relationship, because the body knows about the heart, but not the other way around.

Note that composition has nothing to say about the transferability of parts. A heart can be transplanted from one body to another. However, even after being transplanted, it still meets the requirements for a composition (the heart is now owned by the recipient, and can only be part of the recipient object unless transferred again).

Our ubiquitous Fraction class is a great example of a composition:

This class has two data members: a numerator and a denominator. The numerator and denominator are part of the Fraction (contained within it). They can not belong to more than one Fraction at a time. The numerator and denominator don’t know they are part of a Fraction, they just hold integers. When a Fraction instance is created, the numerator and denominator are created. When the fraction instance is destroyed, the numerator and denominator are destroyed as well.

While object composition models has-a type relationships (a body has-a heart, a fraction has-a denominator), we can be more precise and say that composition models “part-of” relationships (a heart is part-of a body, a numerator is part of a fraction). Composition is often used to model physical relationships, where one object is physically contained inside another.

The parts of a composition can be singular or multiplicative -- for example, a heart is a singular part of the body, but a body contains 10 fingers (which could be modeled as an array).

Implementing compositions

Compositions are one of the easiest relationship types to implement in C++. They are typically created as structs or classes with normal data members. Because these data members exist directly as part of the struct/class, their lifetimes are bound to that of the class instance itself.

Compositions that need to do dynamic allocation or deallocation may be implemented using pointer data members. In this case, the composition class should be responsible for doing all necessary memory management itself (not the user of the class).

In general, if you can design a class using composition, you should design a class using composition. Classes designed using composition are straightforward, flexible, and robust (in that they clean up after themselves nicely).

More examples

Many games and simulations have creatures or objects that move around a board, map, or screen. One thing that all of these creatures/objects have in common is that they all have a location. In this example, we are going to create a creature class that uses a point class to hold the creature’s location.

First, let’s design the point class. Our creature is going to live in a 2d world, so our point class will have 2 dimensions, X and Y. We will assume the world is made up of discrete squares, so these dimensions will always be integers.


Note that because we’ve implemented all of our functions in the header file (for the sake of keeping the example concise), there is no Point2D.cpp.

This Point2d class is a composition of its parts: location values x and y are part-of Point2D, and their lifespan is tied to that of a given Point2D instance.

Now let’s design our Creature. Our Creature is going to have a few properties: a name, which will be a string, and a location, which will be our Point2D class.


This Creature is also a composition of its parts. The creature’s name and location have one parent, and their lifetime is tied to that of the Creature they are part of.

And finally, Main.cpp:

Here’s a transcript of this code being run:

Enter a name for your creature: Marvin
Marvin is at (4, 7)
Enter new X location for creature (-1 to quit): 6
Enter new Y location for creature (-1 to quit): 12
Marvin is at (6, 12)
Enter new X location for creature (-1 to quit): 3
Enter new Y location for creature (-1 to quit): 2
Marvin is at (3, 2)
Enter new X location for creature (-1 to quit): -1

Variants on the composition theme

Although most compositions directly create their parts when the composition is created and directly destroy their parts when the composition is destroyed, there are some variations of composition that bend these rules a bit.

For example:

  • A composition may defer creation of some parts until they are needed. For example, a string class may not create a dynamic array of characters until the user assigns the string some data to hold.
  • A composition may opt to use a part that has been given to it as input rather than create the part itself.
  • A composition may delegate destruction of its parts to some other object (e.g. to a garbage collection routine).

The key point here is that the composition should manage its parts without the user of the composition needing to manage anything.

Composition and subclasses

One question that new programmers often ask when it comes to object composition is, “When should I use a subclass instead of direct implementation of a feature?”. For example, instead of using the Point2D class to implement the Creature’s location, we could have instead just added 2 integers to the Creature class and written code in the Creature class to handle the positioning. However, making Point2D its own class has a number of benefits:

  1. Each individual class can be kept relatively simple and straightforward, focused on performing one task well. This makes those classes easier to write and much easier to understand, as they are more focused. For example, Point2D only worries about point-related stuff, which helps keep it simple.
  2. Each subclass can be self-contained, which makes them reusable. For example, we could reuse our Point2D class in a completely different application. Or if our creature ever needed another point (for example, a destination it was trying to get to), we can simply add another Point2D member variable.
  3. The parent class can have the subclasses do most of the hard work, and instead focus on coordinating the data flow between the subclasses. This helps lower the overall complexity of the parent object, because it can delegate tasks to its children, who already know how to do those tasks. For example, when we move our Creature, it delegates that task to the Point class, which already understands how to set a point. Thus, the Creature class does not have to worry about how such things would be implemented.


A good rule of thumb is that each class should be built to accomplish a single task. That task should either be the storage and manipulation of some kind of data (e.g. Point2D, std::string), OR the coordination of subclasses (e.g. Creature). Ideally not both.

In this case of our example, it makes sense that Creature shouldn’t have to worry about how Points are implemented, or how the name is being stored. Creature’s job isn’t to know those intimate details. Creature’s job is to worry about how to coordinate the data flow and ensure that each of the subclasses knows what it is supposed to do. It’s up to the individual subclasses to worry about how they will do it.

16.3 -- Aggregation
16.1 -- Object relationships

145 comments to 16.2 — Composition

  • yeokaiwei

    Hi Alex,

    Perhaps you could add a term called Entity Component System?

    This is one example of composition that is used in gaming.

    It was used for games like Overwatch.

    This will help learners find examples of composition.


  • Waldo Lemmer

    - `:`:

    - &:

    > A good rule of thumb is that each class should be built to accomplish a single task

    I think this belongs in a "Best practice" block

  • Haldhar Patel

    Hi Alex and nascardriver!
    I am struggling to make this code work can you help me out. I searched everywhere but haven't found a solution.
    I wanted to make a vector of Point2D inside the class Creature with a default size and default Point2D value from the Point2D constructor. I mentioned the errors at the code below:

    >Am I doing it wrong or Is it not possible.

    • Kanaetochi Okiyi

      std::vector<Point2D> m_location( 10, Point2D() )

      A Point2D vector of size ten would be this:

      std::vector<Point2D, 10> m_location;

      You put the size after the type.

    • nascardriver

      Sorry for the late reply

      When you construct a vector with a specific size, it default-constructs that number of elements.

      • Haldhar Patel

        Sorry to say but I am still getting that error , also what is wrong with

        If I try inside the constructor like

        then it works but in the member declaration it doesn't.

        Is my compiler misconfigured?
        Will you mind checking it in yours. Thanks

        • nascardriver

          My bad, you cannot use direct-initialization at member declarations, don't ask me why.

  • Herevei


    Wanted to ask a question regarding Point2D example. Wouldn't it be better to use just one constructor with default parameters' values set to 0?

  • yeokaiwei

    1. Query
    What about the heart being destroyed?
    The body is not destroyed.

    Does the analogy breakdown?

  • Gamer_to_be

    In the creature example, Creature class is a parent class and Point2D class is a subclass, am I right?

  • Rohit Alawadhi

    Why does the code fail if I put const before the function

    and before the first argument i.e. out?

  • Antonio

    Hey, wanted to ask something that I am not very sure of.
    In the following code, when we pass &name and &location, when the initialization happens: m_name{ name }, m_location{ location }
    are the initialized variables references to the memory of the caller/creator of the object? Or are they new copies?

    • nascardriver

      `name` and `location` are references to the caller's variables (Or temporaries, if the caller passed in literals, eg. `Creature{ "Antonio", {} };`).
      `m_name` and `m_location` are full variables, we're using their copy constructors to create copies of the referenced variables.
      If `name` and `location` weren't references, we'd create a copy of the callers variables when the constructor is called and then copy them again to initialize the members. By using references, we only need to copy each variable once.

      • salah

        Hi Nascardriver,
        are they (name, location) destroyed after the function end, or when they do their job ?

        • nascardriver

          `name` and `location` are references to the caller's variables. This constructor doesn't change their lifetime. `m_name` and `m_location` are members of `Creature`, they live as long as this instance of `Creature` lives.

          • salah

            I mean the constructor parameters. I am not talking about the object variables in which their life is tied with their object, I am talking about these parameters (const std::string &name, const Point2D &location).they get destroyed after the constructor ends, am I right ?

  • amusca

    Hi, For creature/point example, I separated the code into header and cpp file for both Creature and Point2D classes. I am getting error "attempting to reference a deleted function function"  on the overloaded output operator friend function. Any idea why?  Note: I am coding using Visual Studio 2017.

    example of my set up

    friend std::ostream& operator<<(std::ostream& out, const Point2D &point);

    std::ostream& operator<<(std::ostream& out, const Point2D &point);

            out << "(" << point.m_x << ", " << point.m_y << ")";
            return out;

    friend std::ostream& operator<<(std::ostream& out, const Creature &creature);

    std::ostream& operator<<(std::ostream& out, const Creature &creature)
            out << creature.m_name << " is at " << creature.m_location;
            return out;

    • nascardriver

      Please post the full code and error message. I can't tell whats going wrong from the information you provided.

      • amusca

        Error C2280 'std::basic_ostream<char,std::char_traits<char>>::basic_ostream(const std::basic_ostream<char,std::char_traits<char>> &)': attempting to reference a deleted function

  • song

    Hi, Alex.
    Thanks for your sharing this great knowledge.
    I've been learning so much from your tutorial.

    I have a seemingly stupid question. It seems stupid because no one has questioned yet...

    I would like to know how the overloaded operator " << " can print the ""creature location"". I can't find any invoking " << " operator in the "main.cpp".

    Thanks to you again.
    Sincerely, Song

  • Mukesh Kumar

    If I don't want to use overload operator how to write this piece of code.

    friend std::ostream& operator<<(std::ostream& out, const Point2D &point)
            out << "(" << point.m_x << ", " << point.m_y << ")";
            return out;

  • Bruno Luiz Demarchi

    Hi Alex!

    I have a question. Can I still access normally an object wich I passed to another one to make a composition?


    This is just a test code as example. My question is, are test1 == test2? Can I keep using my encTest normally even after passing it to my motorTest?

    • Hi Bruno!

      * Line 7, 19, 32, 33: Initialize your variables with brace initializers. You used direct initialization.
      * Line 4, 16, 30: Initialize your variables with brace initializers.
      * Line 10: Missing braces.
      * Don't use @uint32_t. Use @std::uint_fast32_t or @std::uint_least32_t.
      * @main invalid declaration.

      Neither @encTest or @motorTest modified their copy the ticks, so @test1 and @test2 compare equal.
      But @Motor isn't storing @enc by pointer or reference. Modifying @encTest or @motorTest does not affect the other.

      • Bruno Luiz Demarchi

        Thanks man!

        Actually I didn't know that i could (and should) use {} instead of (), I'm kind of new in c++.

        What are the diferences between uint32_t and uint_fast32_t? Because into the stdint.h they are define as:

        typedef unsigned           int uint32_t;
        typedef unsigned           int uint_fast32_t;

        To me they work as the same, that's why I choose to work with uint32_t.

        How could I store @enc by point or reference?

        Again, thanks!!

        • > I didn't know that i could (and should) use {} instead of ()
          Lesson 1.4
          Brace initializers disallow implicit casts and can be used almost everywhere.

          > What are the diferences between uint32_t and uint_fast32_t?
          Lesson D.2.4a
          @std::int*_t isn't guaranteed to be available.

          > How could I store @enc by point or reference?
          Lesson 6.7 to 7.8

  • It would be better if we leave 'parent' and 'child' words for Inheritance; for example in "The complex object is sometimes called the whole, or the parent. The simpler object is often called the part, child, or component.", I think. We can call the whole to be the 'Owner' and component to be 'Ownee'.

    • Alex

      That terminology makes sense for compositions, but not for other types of relationships that are non-owning. Parent-child isn't intended to imply anything about ownership.

  • Is operator overloading compulsory here?

    • Alex

      If I'm understanding your question correctly, no. It's just used to allow our user-defined class to be printed using std::cout and operator<<. If you don't care about that, then there's no need to overload anything.

    • beginnerCoder

      Hello! When defining the specific constructor in the Creature class, is it possible to initialize the parameters to default values like this:

      Creature(const std::string &name="unnamed", const Point2D &location())
              : m_name(name), m_location(location)

      to insert a creature with no name at the origin? I am in doubt about the syntax for initializing the location parameter. If I'm not mistaken location() should simply call the default constructor of Point2D if no parameter is specified by the user.

      • References have to reference something. @location doesn't reference anything at there's nothing it could reference. Use @std::reference_wrapper and set it to a nullptr or overload to constructor with a version that doesn't take a location.

  • AJ

    why we should use default constructor and setters both in creature program?? because both have same meanings.

  • seriouslysupersonic


    Regarding the #include directives @main, is it better practice to explicitly include the child class?

  • hrmn

    Point2D m_location; inside class is composition  not aggregation right?, as it's not a pointer or reference

  • Abdul mannan

    Can we do composition if parent class is abstract?

  • boredprogrammer

    I think, a good thing to add to these parts of the tutorial are the UML diagrams where the ideas are extracted from. Just to post a picture of the UML diagram used to represent compositions, aggregations, etc. I think the direct connection from modelling a piece of software via UML to the implementation in ANY language, would make more evident the explained here. Ie, aggregations exists even when some lenguages don't use pointers or even references, but there are ways to have the same model of parts.

    Just an idea... and also, boxes, arrows, diagrams are nice!

  • Aniket

    You haven't answered the question "When should I use a subclass instead of direct implementation of a feature?"
    Instead, after that question you have been answering "Why should I use a subclass instead of direct implementation of a feature?"

    I want to understand that when part clearly.

    • Alex

      You should generally make a member a class type when the storage or manipulation of that member is non-trivial. For example, if a member needs to represent a point or a fraction, you should use a class, because the storage and manipulation of that data isn't trivial. If you need to store an employee's ID or age, use an int, because that is trivial.

  • Ritesh

    Hey Alex,
    I wrote the above program of creatures and point2d, by creating a Creature header and its cpp and same for Point2D I created both its header and cpp
    I defined the friend function and set functions in the cpp files. heres the code

    #pragma once
    class Point2D
        int m_x;
        int m_y;
        Point2D(int x = 0, int y = 0) :m_x(x), m_y(y)

        friend std::ostream& operator<<(std::ostream &out, const Point2D &obj);
        void setPoint(int x = 0, int y = 0);

    #include "Point2D.h"
    std::ostream& operator<<(std::ostream &out, const Point2D &obj)
        out << "(" << obj.m_x << "," << obj.m_y << ")\n";
        return out;
    void Point2D::setPoint(int x, int y)
        m_x = x;
        m_y = y;

    #pragma once
    #include "Point2D.h"
    class Creature
        std::string m_name;
        Point2D m_location;
        Creature(const std::string &name, const Point2D &obj) :m_name(name), m_location(obj)

        friend std::ostream& operator<<(std::ostream &out, const Creature &obj);
        void moveTo(int x = 0, int y = 0);

    #include "Creature.h"
    std::ostream& operator<<(std::ostream &out, const Creature &obj)
        out << obj.m_name << " is at " << obj.m_location<<'\n';
        return out;
    void Creature::moveTo(int x, int y)
        m_location.setPoint(x, y);

    and Finally main.cpp
    #include "stdafx.h"
    #include "Point2D.h"
    #include "Creature.h"
    using namespace std;
    int main()
        cout << "Enter the name of your creature";
        string name;
        cin >> name;
        Creature creature(name, Point2D(4, 12));
        cout << creature; // this line gives linker error
        return 0;
    and the linker error is LNK2019, unresolved externals referenced in main, and when I'll comment this line cout<< creature, then code compiles and links fine. I am not understanding what's going wrong in this code, why my linker is not linking the definition of the overloaded cout << creature;

    • Alex

      Not sure. When I put this all in one file, it compiled fine. Therefore, it appears like the issue here is that the linker is not able to find the definition of operator<< for Creature. That suggests to me that maybe you forgot to add Creature.cpp to your project, so it's not actually being compiled/linked when you compile your program.

  • What I learn from this section.

    Composition makes programmers less worry about the deletion of the object. In most of the case, this type of relation guarantee the existance of the member in such a way it automatically knows when to birth and to death.

    Some questions that I do not understand:

    What is the difference between a default constructor and a specific one? Why we need two here? What is the meaning of the default constructor? What kind of date type is m_x and m_y in the default constructor?

    What does it mean? If I don't want to use overload operator how to write this piece of code?

    • nascardriver

      Hi Ryder!

      > What is the difference between a default constructor and a specific one? Why we need two here?

      > What is the meaning of the default constructor?
      The default constructor gets called whenever you create an object without passing arguments to the constructor.

      > What kind of date type is m_x and m_y in the default constructor?
      The are the local variables @m_x and @m_y

      > What does it mean? If I don’t want to use overload operator how to write this piece of code?
      You can't do that without overloading the << operator.

  • Nur

    Hello Alex,
    Hope you are doing well.
    I have a question regarding to above given Creature class.
    My question:

    Can we consider internally (or separately) the relationship between Creature class's object and std::ostream's object std::cout as Dependencies, although you have given as a composition between Creature and Point2D classes?

    If what I said is correct then it is worth noting that the concepts of composition and dependencies are not mutually exclusive, and can be mixed freely within the same class.
    Am I right?. If not, please could you clarify it?

    Thanks for a great tutorial!I have never seen such a tutorial in C++. It is the most precious one.

    • Alex

      Yes, I'd say std::cout is a dependency in this case, as the class uses it temporarily. You're correct in that the various relationships aren't exclusive -- a single class might contain an composition element, an association element, and a dependency.

  • Nurlan

    Hello Alex,
    I hope you are fine.
    As you said to qualify as a composition, an object and a part must have the  following relationship:
    One of them is The part (member) can only belong to one object (class) at a time.

    And you gave the Fraction class  as a great example of a composition:

    class Fraction
        int m_numerator;
        int m_denominator;

        Fraction(int numerator=0, int denominator=1):
        m_numerator(numerator), m_denomin1ator(denominator)

    //Now, let's write the main() function by myself
    int main()
      Fraction f1(3, 4);
      Fraction &f2=f1;//is this still composition since now part (members)belongs two //objects, which has the same address,i.e. f2 is reference to f1;

    Is this composition even it is belongs to two objects which has the same address, or it is considered to one object since it is alias name of f1?
    Thanks in advance!

    • Alex

      Fraction is a composition since the parts (m_numerator and m_denominator) belong to the whole (the Fraction object).

      The fact that you have a second variable referencing the first variable is immaterial. f1 owns its members. f2 is just a reference to f1, and has no bearing on ownership.

  • Zoran

    In Creature constructor, why do you pass name by value, unlike location?

    That is, instead of

    wouldn't this be better:

    Is there a reason?

  • Omri

    "the heart is now owned by the donor, and can only be part of the donor object unless transferred again"
    "the heart is now owned by the receiver only, and can only be part of the receiver object (no more belongs to the doner, no mutual ownership) until transferred again"

  • Omri

    "For example, a heart is an part of a person’s body."
    "For example, a heart is *a* part of a person’s body."

  • Rohit

    Hi Alex!

    1) Suppose we create a .h file which contain function declarations and another .cpp file which contains      function definition. Now if we add .h file to our program, does it itself include .cpp file or we need to add .cpp file also and how?

    2) Is file handling discussed in these tutorials?

  • robbe

    I'm probably wrong but since a programmer has no way of knowing a Point2D object contains merely fundamental type member variables, shouldn't the m_location variable (of type Point2D) in the Creature class be dynamically allocated and destroyed according to RAII?

    • Alex

      No. Classes are expected to clean up after themselves. Point2D should clean up itself when it is destroyed regardless of how it is implemented. Any class using Point2D should not need to worry about this, regardless of whether the class is dynamically allocated or not.

  • Michiel

    In main.cpp you forgot to add std:: before the first cout

Leave a Comment

Put all code inside code tags: [code]your code here[/code]