C ++ Decorator added to std :: vector

I have a base class for writing, and I want to add additional fields and comparison functions using decorators and be able to bind decorators (records can have an email or date of birth, or both), I will also have many such decorators ; one for each additional field and its comparison function. Once this is done, I'm going to add objects to the vector using the base class pointer.

Here is a sample code:

class BaseRecord
{
public:
    virtual bool Compare();     // defined elsewhere

protected:
    std::string m_strName;
    std::string m_strAddress:
};

class BaseDecorator : public BaseRecord
{
public:
    BaseDecorator(BaseRecord *pBase) : m_pBase(pBase){}

    bool Compare()
    {
        return m_pBase->Compare();
    }

private:
    BaseRecord *m_pBase;
};

class EmailDecorator : public BaseDecorator
{
public:
    EmailDecorator(BaseRecord *pBase) : EmailDecorator(pBase){}

    bool Compare()
    {
        if (!CompareEmail())        // defined elsewhere
        {
            return false;
        }

        BaseDecorator::Compare();
    }

private:
    std::string m_strEmail
};

class DOBDecorator : public BaseDecorator
{
public:
    DOBDecorator(BaseRecord *pBase) : DOBDecorator(pBase){}

    bool Compare()
    {
        if (!CompareDOB())      // defined elsewhere
        {
            return false;
        }

        BaseDecorator::Compare();
    }

private:
    std::string m_strDOB;
};

These are classes. Now I would like to add them to the vector:

vector<BaseRecord *> m_vecRecords;

BaseRecord pRecord = new BaseRecord();

// wrong - copies pointer only to vector
m_vecRecords.push_back(pRecord);

// OK - default copy constructor for BaseRecord used
m_vecRecords.push_back(new BaseRecord(*pRecord));

// now chain the decorators

// pRecord is a BaseRecord
BaseRecord pRecord = new EmailDecorator(pRecord);

//wrong - copies pointer only to vector
m_vecRecords.push_back(pRecord);

// ??? needs copy constructor
m_vecRecords.push_back(new EmailDecorator(*pRecord));

// pRecord is an EmailDecorator
BaseRecord pRecord = new DOBDecorator(pRecord);

// wrong - copies pointer only to vector
m_vecRecords.push_back(pRecord);

// ??? needs copy constructor
m_vecRecords.push_back(new DOBDecorator(*pRecord));

Now try writing copy constructors:

// should p be an EmailDecorator *, or a BaseDecorator * ?
EmailDecorator::EmailDecorator(const EmailDecorator *p)
{
    // this will leak - no delete in the destructor
    // I have not supplied a destructor
    m_pBase = new BaseDectorator(p);
    m_strEmail = p->m_strEmail;
}

// should p be a DOBDecorator *, or  BaseDecorator * ?
// in the above example, when the copy constructor is needed, it is an EmailDecorator *

DOBDecorator::DOBDecorator(const DOBDecorator *p)
{
    // this will leak - no delete in the destructor
    // I have not supplied a destructor
    m_pBase = new BaseDectorator(p);
    m_strDOB = p->m_strDOB;
}

, ? , - ?

+4
1

, Decorator; , ++.

Decorator , . , , BaseDecorator name:

.

++, , , . , , , ++ .

, , ?


, :

class IRecord {
public:
    virtual bool lessThan(IRecord const& other) const = 0;
};

, ; , , , this EmailDecorator, EmailDecorator - .

, , :

class RecordDecorator: public IRecord {
protected:
    RecordDecorator(std::unique_ptr<IRecord> r): _decorated(std::move(r)) {}

private:
    std::unique_ptr<IRecord> _decorated;
};

:

class BaseRecord final: public IRecord {
public:
    BaseRecord(std::string name, std::string address):
        _name(std::move(name)), _address(std::move(address)) {}

    virtual bool lessThan(IRecord const& record) const override;

private:
    std::string _name;
    std::string _address;
}; // class BaseRecord

, , ( , ) :

class Record {
public:
    Record(std::string name, std::string address):
        _data(std::make_unique<BaseRecord>(std::move(name), std::move(address)) {}

    bool lessThan(Record const& other) const {
        return _data->lessThan(other._data);
    }

    template <typename D, typename... Args>
    void decorate(Args&&... args) {
        _data = std::make_unique<D>(std::move(_data), std::forward<Args>(args)...);
    }

private:
    std::unique_ptr<IRecord> _data;
}; // class Record

:

  • ,
  • -,
  • ( )

, , Record ( ), std::unique_ptr .

, virtual std::unique_ptr<IRecord> clone() const = 0 (*) IRecord, . RecordDecorator:

class RecordDecorator: public IRecord {
protected:
    RecordDecorator(std::unique_ptr<IRecord> r): _decorated(std::move(r)) {}

    RecordDecorator(RecordDecorator const& other):
        _decorated(other._decorated->clone()) {}

    RecordDecorator& operator=(RecordDecorator const& other) {
        if (this == &other) { return *this; }
        _decorated = other._decorated.clone();
        return *this;
    }

    // These two got disabled when we wrote our own copy constructor
    // and copy assignment operator, so let re-enable them.
    RecordDecorator(RecordDecorator&&) = default;
    RecordDecorator& operator=(RecordDecorator&&) = default;

private:
    std::unique_ptr<IRecord> _decorated;
};

, RecordDecorator, - --, , .

Record :

Record::Record(Record const& other):
    _data(other._data.clone())
{}

Record& Record::operator=(Record const& other) {
    if (this == &other) { return *this; }
    _data = other._data.clone();
    return *this;
}

// These two got disabled when we wrote our own copy constructor
// and copy assignment operator, so let re-enable them.
Record::Record(Record&&) = default;
Record& Record::operator=(Record&&) = default;

, :

class EmailDecorator final: public RecordDecorator {
public:
    EmailDecorator(std::unique_ptr<IRecord> base, std::string email):
        RecordDecorator(std::move(base)), _email(email) {}

    virtual std::unique_ptr<IRecord> clone() const override {
        return std::make_unique<EmailDecorator>(*this);
    }

    virtual bool lessThan(IRecord const&) const override; // up to you ;)

private:
    std::string _email;
}; // class EmailDecorator

int main() {
    Record record{"John, Doe", "12345 Mimosa Road, 3245 Washington DC"};
    record.decorate<EmailDecorator>("john.doe@aol.com");

    std::vector<Record> vec;
    vec.push_back(record); // make a copy
    vec.back().decorate<EmailDecorator>("doe.john@msn.com"); // another e-mail!
}

... ... : lessThan .

+2

Source: https://habr.com/ru/post/1535938/


All Articles