gpt4 book ai didi

C++ 装饰器添加到 std::vector

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:10:16 26 4
gpt4 key购买 nike

我有一个记录的基类,想使用装饰器添加额外的字段和比较函数,并能够链接装饰器(记录可以有电子邮件,或出生日期,或两者都有,或没有) .我也会有很多这样的装饰器;每个附加字段一个,及其比较功能。完成此操作后,我将使用基类指针将对象添加到 vector 中。

代码如下:

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;
};

那些是类。我现在想做的是将它们添加到一个 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));

现在尝试编写复制构造函数:

// 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;
}

那么我该如何编写复制构造函数来进行深复制,并能够释放分配的内存呢?我觉得我错过了一些东西,有一种方法可以做到这一点而不必提供复制构造函数吗?

最佳答案

就装饰器而言,您并没有太大的偏差;不幸的是,您在 C++ 方面的差距很大。

Decorator方面,您遇到的主要问题是您的接口(interface) 不应该有任何值(value)。否则,就像这里的情况一样,BaseDecorator对象有 至少 两个 name字段:

  • 一个来自它的基类
  • 成员之一

并且您忘记了从基类初始化一个。

就 C++ 而言,不幸的是这变得复杂,因为您没有考虑所有权。在具有垃圾收集器的语言中,您可以偷工减料,但在 C++ 中,这是行不通的。

那么让我们纠正这个问题,我们应该吗?


首先,我们需要一个干净的界面:

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

我会让您了解如何实际比较两条记录;使用装饰器方法可能并不容易,因为不能保证仅仅因为 this是一个 EmailDecorator , other 也有一个 EmailDecorator 某处 在它的链中。

然后,我们可以构建装饰器方法,我们将使用强大的所有权声明来实现:

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

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

我们也可以 build 我们的第一 block 石头:

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's 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's 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实际上。

关于C++ 装饰器添加到 std::vector,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22989530/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com