tmaric
tmaric

Reputation: 5477

How to decorate objects in a single line of code using the decorator pattern in C++?

I am learning the decorator pattern from the Head First Design Patterns book , and here's what I've coded (C++) to get the pattern to work:

#include <iostream>


class AbstractType
{
public: 
    virtual double value() const = 0;
};


class FirstConcreteType
    :
    public AbstractType
{
public: 
    double value() const 
    {
        return 1; 
    }
};

class SecondConcreteType
    : 
    public AbstractType
{
public:
    double value() const
    {
        return 2;
    }
};

class DecoratorType
    :
    public AbstractType
{
    const AbstractType* decoratedObject_; 

public:

    DecoratorType(const AbstractType& abstractObject)
        :
    decoratedObject_(&abstractObject)
    {}

    DecoratorType(const DecoratorType& decoratorObject)
        :
    decoratedObject_(&decoratorObject)
    {}

    virtual double value() const = 0; 

    const AbstractType& getObject() const
    {
        return *decoratedObject_; 
    }
};

class FirstDecoratorType
    :
    public DecoratorType
{
public:
    FirstDecoratorType(const AbstractType& abstractObject)
        :
    DecoratorType(abstractObject)
    {}

    FirstDecoratorType(const DecoratorType& decoratorObject)
        :
    DecoratorType(decoratorObject)
    {}

    double value() const
    {
        const AbstractType& object = getObject(); 

        return 1 + object.value(); 
    }
};

class SecondDecoratorType
    :
    public DecoratorType
{
public:
    SecondDecoratorType(const AbstractType& abstractObject)
        :
    DecoratorType(abstractObject)
    {}

    SecondDecoratorType(const DecoratorType& decoratorObject)
        :
    DecoratorType(decoratorObject)
    {}

    double value() const
    {
        const AbstractType& object = getObject(); 

        return 2 + object.value(); 
    }
};

using namespace std;

int main()
{
    // When I decorate sequentially, it works fine

    SecondConcreteType secondConc;

    FirstDecoratorType firstDec(secondConc); 
    cout << firstDec.value() << endl;

    SecondDecoratorType secondDec(firstDec); 
    cout << secondDec.value() << endl;

    FirstDecoratorType firstDecSecond (secondDec); 
    cout << firstDecSecond.value() << endl; 

    // Decorating in a single line, messes things up, since there is no
    // constructor taking the value argument defined.  
    //FirstDecoratorType firstDynamicDec (SecondConcreteType()); 
    //cout << firstDynamicDec.value() << endl;

    return 0;
};

In the main program, the object of theh ConcreteType must be created first, and then it is decorated using composition of the pointer to the AbstractType (within the DecoratorType). It works fine, if I create the concrete objects, and create the new decorated objects one after another..

What do I need to do in order for the DecoratorType to be able to decorate objects using composition in a single line of code (commented out line in the example code)? Would something like this be useful at all in the "real world"? I (obviously) don't have a lot of experience in using design patterns.. so it's difficult for me to see what functionality I should aim at.

EDIT:

Here's a version working with basic pointers (valgrind shows no memory leaks, and states that no memory leaks are possible):

#include <iostream>


class AbstractType
{
    public: 
        virtual double value() const = 0;

        virtual ~AbstractType() {}; 
};

class FirstConcreteType
:
    public AbstractType
{
    public: 
        double value() const 
        {
            return 1; 
        }
};

class SecondConcreteType
: 
    public AbstractType
{
    public:
        double value() const
        {
            return 2;
        }
};

class DecoratorType
:
    public AbstractType
{
    const AbstractType* decoratedObject_; 
    bool own_;

    public:

        DecoratorType(const AbstractType& abstractObject)
            :
                decoratedObject_(&abstractObject), 
                own_(false)
        {}

        DecoratorType(const DecoratorType& decoratorObject)
            :
                decoratedObject_(&decoratorObject), 
                own_(false)

        {}

        DecoratorType (AbstractType* abstractPtr)
            : 
                decoratedObject_(abstractPtr), 
                own_(true)
        {}

        DecoratorType (DecoratorType* decoratorPtr)
            :
                decoratedObject_(decoratorPtr), 
                own_(true)
        {}

        virtual ~DecoratorType()
        {
            if (own_)
            {
                delete decoratedObject_; 
                decoratedObject_ = 0;
            }
        }

        virtual double value() const = 0; 

        const AbstractType& getObject() const
        {
            return *decoratedObject_; 
        }
};

class FirstDecoratorType
:
    public DecoratorType
{
    public:
        FirstDecoratorType(const AbstractType& abstractObject)
            :
                DecoratorType(abstractObject)
        {}

        FirstDecoratorType(const DecoratorType& decoratorObject)
            :
                DecoratorType(decoratorObject)
        {}

        FirstDecoratorType (AbstractType* abstractPtr)
            :
                DecoratorType(abstractPtr)
        {}

        FirstDecoratorType (FirstDecoratorType* decoratorPtr)
            :
                DecoratorType(decoratorPtr)
        {}


        double value() const
        {
            const AbstractType& object = getObject(); 

            return 1 + object.value(); 
        }
};

class SecondDecoratorType
:
    public DecoratorType
{
    public:
        SecondDecoratorType(const AbstractType& abstractObject)
            :
                DecoratorType(abstractObject)
        {}

        SecondDecoratorType(const DecoratorType& decoratorObject)
            :
                DecoratorType(decoratorObject)
        {}

        SecondDecoratorType (AbstractType* abstractPtr)
            :
                DecoratorType(abstractPtr)
        {}

        SecondDecoratorType (SecondDecoratorType* decoratorPtr)
            :
                DecoratorType(decoratorPtr)
        {}

        double value() const
        {
            const AbstractType& object = getObject(); 

            return 2 + object.value(); 
        }
};

using namespace std;

int main()
{
    // When I decorate sequentially, it works fine

    SecondConcreteType secondConc;

    FirstDecoratorType firstDec(secondConc); 
    cout << firstDec.value() << endl;

    SecondDecoratorType secondDec(firstDec); 
    cout << secondDec.value() << endl;

    FirstDecoratorType firstDecSecond (secondDec); 
    cout << firstDecSecond.value() << endl; 

    // Decorating in a single line, messes things up, since there is no
    // constructor taking the value argument defined.  
    FirstDecoratorType firstDynamicDec (new SecondDecoratorType (
           new FirstDecoratorType (new SecondConcreteType()))); 

    cout << firstDynamicDec.value() << endl;

    return 0;
};

Upvotes: 0

Views: 790

Answers (2)

Bart van Ingen Schenau
Bart van Ingen Schenau

Reputation: 15768

The first problem is that

FirstDecoratorType firstDynamicDec (SecondConcreteType()); 

does not declare an object at all, but a function. This is called the most vexing parse of C++.

But even when you work around that, you have the problem that temporary objects (such as created by SecondConcreteTpe()) only exist until the end of the expression, so the pointer within FirstDecoratorType would be invalid before you can do anything useful with it.
You can resolve this by using smart pointers to hold the decorated type within the decorator (for example, std::unique_ptr). This makes the decorator responsible for cleaning up the decorated type.

Upvotes: 1

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361522

FirstDecoratorType firstDynamicDec (SecondConcreteType()); 

The problem with this is that it does NOT define an object. Instead, it declares a function. Look for most-vexing-parse in C++ on this site, you will get lots of topics on it.

Short explanation : the function name is firstDynamicDec whose return type is FirstDecoratorType and it takes parameter which is again a function returning SecondConcreteType and taking no argument.

Upvotes: 4

Related Questions