Thread: Aggregation vs Composition

  1. #1
    Registered User
    Join Date
    Mar 2016
    Posts
    110

    Aggregation vs Composition

    I have read all StackOverflow articles. Many other articles. Book posts and blogs and still struggling to understand the difference between the two.
    From what I know:

    Composition means that if A is an composite of B, then the instance of B may only exist in through an instance of A.

    Aggregation means that if A is an aggregate of B, then the instance of B may exist in other instances other than in A.

    Then a few examples are given such as a car with wheels and rooms and houses which really depend on your modelling requirements. My question is, how are these ultimately IMPLEMENTED in C++ with an example?

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Composition: B is a member object or member smart pointer with exclusive ownership (unique_ptr, or shared_ptr that is never exposed as part of the interface)

    Aggregation: B could be an object or a smart pointer with ownership; A has a member (smart) pointer to B, e.g., if B is a shared_ptr, it could be another shared_ptr or a weak_ptr. A member reference may be possible too.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Mar 2016
    Posts
    110
    I get that but how would the difference in implementation look? Ill give an example. Ive made 1 superclass called Asset and 3 subclasses which derive from Asset and they are called Stock, Bond and Saving. I made 5 instances of stocks, bonds and savings and threw them in a container class called AssetList. The interface and implementation are shown below. Note that I used the Qt framework and so some data structures are not part of the standard library. Please note that according to my understanding the below is a COMPOSITE setup. What would I need to tweak to make it an AGGREGATION?:

    Code:
    #ifndef ASSET_H
    #define ASSET_H
    
    #include <QString>
    #include <QDate>
    
    class Asset
    {
    public:
        Asset(QString des, QDate dat);
        virtual double value() = 0;
        QString getDescription();
        QString getType();
    protected:
        QString type;
        QDate date;
    private:
        QString description;
    };
    
    #endif // ASSET_H
    Code:
    #include "asset.h"
    
    Asset::Asset(QString des, QDate dat) : description(des), date(dat){
    
    }
    
    QString Asset::getDescription(){
        return description;
    }
    
    QString Asset::getType(){
        return type;
    }
    Code:
    #ifndef STOCK_H
    #define STOCK_H
    
    #include "asset.h"
    #include <QString>
    #include <QDate>
    
    class Stock : public Asset
    {
    public:
        Stock(QString des, QDate dat, int nsh, double spr);
        double value();
        void setPrice(double np);
    private:
        int numShares;
        double sharePrice;
    };
    
    #endif // STOCK_H
    Code:
    #include "stock.h"
    
    Stock::Stock(QString des, QDate dat, int nsh, double spr) : Asset(des, dat), numShares(nsh), sharePrice(spr){
        type = "Stock";
    }
    
    double Stock::value(){
        return sharePrice * numShares;
    }
    
    void Stock::setPrice(double np){
        sharePrice = np;
    }
    Code:
    #ifndef BOND_H
    #define BOND_H
    
    #include "asset.h"
    
    class Bond : public Asset
    {
    public:
        Bond(QString des, QDate dat, double fva, double yield);
        double value();
    private:
        double faceValue;
        double yield;
    };
    
    #endif // BOND_H
    Code:
    #include "bond.h"
    #include <QDate>
    #include <QDebug>
    
    Bond::Bond(QString des, QDate dat, double fva, double yie) : Asset(des, dat), faceValue(fva), yield(yie){
        type = "Bond";
    }
    
    double Bond::value(){
        int bondYears =QDate::currentDate().year() -  date.year();
        double faceValue = this -> faceValue;
        double interestEarned = (yield/100) * bondYears * faceValue;
        double value = faceValue + interestEarned;
        //qDebug() << "bond value is: " ;
        return value;
    }
    Code:
    #ifndef SAVING_H
    #define SAVING_H
    
    #include "asset.h"
    
    class Saving : public Asset
    {
    public:
        Saving(QString des, QDate dat, double cva, double ira);
        double value();
        void changeValue(double amount);
        void addInterest();
    private:
        double currentValue;
        double interestRate;
    };
    
    #endif // SAVING_H
    Code:
    #include "saving.h"
    #include <QDebug>
    
    Saving::Saving(QString des, QDate dat, double cva, double ira) : Asset(des, dat), currentValue(cva), interestRate(ira){
        type = "Saving";
    }
    
    double Saving::value(){
        return currentValue;
    }
    
    void Saving::changeValue(double amount){
        currentValue += amount;
    }
    
    void Saving::addInterest(){
        currentValue *= (1 + interestRate/100);
    }
    Code:
    #ifndef ASSETLIST_H
    #define ASSETLIST_H
    
    #include <QList>
    #include "asset.h"
    
    class AssetList : public QList<Asset*>
    {
    public:
        AssetList();
        bool addAsset(Asset* a);
        Asset* findAsset(QString des);
        double totalValue(QString typ);
    private:
        QList <Asset*> listOfAssets;
    };
    
    #endif // ASSETLIST_H
    Code:
    #include "assetlist.h"
    #include <iostream>
    
    using namespace std;
    
    AssetList::AssetList(){
    
    }
    
    bool AssetList::addAsset(Asset* a){
        if(!listOfAssets.contains(a)){
             listOfAssets.append(a);
             return true;
        }
        cout << "Asset is a duplicate. Asset is not added to the asset list" << endl;
        return false;
    }
    
    Asset* AssetList::findAsset(QString des){
        for(Asset *iterator : listOfAssets){
            if((*iterator).getDescription() == des){
                return iterator;
            }
        }
        return NULL;
    }
    
    double AssetList::totalValue(QString typ){
        double sumValue = 0;
        for(Asset *iterator : listOfAssets){
            if(typ == iterator->getType()){
                sumValue += iterator->value();
            }
        }
        return sumValue;
    }

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Uh. Why did you go for such a complex example? I can't make head or tail where you want to use aggregation. Just create an object, then create another object whose constructor takes a pointer to the first object so that a member pointer can be initialised. Done!

    Quote Originally Posted by Vespasian_2
    Please note that according to my understanding the below is a COMPOSITE setup.
    Yes, but you're complicating it by having so many objects and involving inheritance. You want the container to use aggregation instead? What do you want?
    Last edited by laserlight; 05-04-2019 at 04:45 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Mar 2016
    Posts
    110
    Thats the problems i'm having. I cant think of the minimum C++ example that demonstrates the difference between the two. I just know through a textbook that what I included above is composition.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Code:
    class DrivingLicence
    {
        // ...
    };
    
    class Car
    {
        // ...
    };
    
    class Driver
    {
        // ...
    private:
        DrivingLicence licence;
        std::vector<Car*> cars;
    };
    In this model, the relationship between Driver and DrivingLicence is composition: if the driver dies (modelled by the destruction of the Driver object), the driving licence cannot be inherited, so it effectively no longer exists, hence the DrivingLicence object will be destroyed. The relationship between Driver and Car is aggregation: while the driver does have a number of cars that he/she drives, if any of the cars is destroyed, the driver doesn't necessarily die, and likewise if the driver dies, the cars might not be involved at all, so other drivers could drive them.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Mar 2016
    Posts
    110
    Quote Originally Posted by laserlight View Post
    Code:
    class DrivingLicence
    {
        // ...
    };
    
    class Car
    {
        // ...
    };
    
    class Driver
    {
        // ...
    private:
        DrivingLicence licence;
        std::vector<Car*> cars;
    };
    In this model, the relationship between Driver and DrivingLicence is composition: if the driver dies (modelled by the destruction of the Driver object), the driving licence cannot be inherited, so it effectively no longer exists, hence the DrivingLicence object will be destroyed. The relationship between Driver and Car is aggregation: while the driver does have a number of cars that he/she drives, if any of the cars is destroyed, the driver doesn't necessarily die, and likewise if the driver dies, the cars might not be involved at all, so other drivers could drive them.
    OK, I assume that this is also a composition between Driver and license?

    Code:
    class Driver
    {
        // ...
    private:
        DrivingLicence *licence = new DrivingLicense;
        std::vector<Car*> cars;
        ~Driver();
    };

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Use a std::unique_ptr<DrivingLicense> and the answer will be clearly a yes (but even then it's possible to design otherwise). If not, it depends.

    For example, in the same code example I showed you in post #6, I could make it composition instead for cars by making it such that the Driver interface doesn't allow for any Car pointer to be provided externally, but rather the Driver object owns the Car objects through the pointers stored in the member vector.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Mar 2016
    Posts
    110
    I think I got you. Its a lot more nuanced than I initially thought.

  10. #10
    Registered User
    Join Date
    Mar 2016
    Posts
    110
    I think I got you, thanks!. Its a lot more nuanced than I initially thought.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Aggregation
    By 4c0 in forum C++ Programming
    Replies: 1
    Last Post: 04-04-2013, 08:12 PM
  2. Can we replace composition with aggregation?
    By mateen anwar in forum C Programming
    Replies: 3
    Last Post: 02-15-2013, 10:00 PM
  3. Aggregation question
    By SterlingM in forum C++ Programming
    Replies: 7
    Last Post: 11-11-2009, 11:30 PM
  4. Aggregation (sort of),
    By Terran in forum C++ Programming
    Replies: 13
    Last Post: 06-09-2008, 02:59 AM
  5. difference between aggregation and composition
    By anil_beloved in forum C Programming
    Replies: 1
    Last Post: 10-18-2004, 12:17 PM

Tags for this Thread