【问题标题】:Replace shared_ptr object with another one用另一个替换 shared_ptr 对象
【发布时间】:2018-06-23 14:24:23
【问题描述】:

基本上,我有基类Employee,里面有enum class,派生类WorkerInternManager 有来自enum 的指定字段来描述它们。

class Employee {
public:
    enum class Status {
        Intern,
        Worker,
        Manager
    };
protected:

    int employeeID;
    std::string Name;
    std::string Surname;
    int Salary;
    bool Hired;
...
}

class Worker : public Employee {

protected:

    Status status = Status::Worker;
}

// "Intern" and "Manager" same way.

我将对象存储在vector<shared_ptr<Employee>> Firm; 中,并通过sourceEmployee[index] 引用对其进行修改。

我想做的是:

提升/降级员工,如何?我想寻找指定的员工并检查他的状态。如果是Worker,我想删除Worker class 对象并改为创建Manager 对象,并从Worker 保存所有字段,例如:姓名、姓氏等。

我的原型(不工作)看起来像这样:

    auto it = std::find_if(sourceEmployee.begin(), sourceEmployee.end(),
                      [&sourceEmployee, id](const auto &obj) { return obj->getID() == id; });
    auto index = std::distance(sourceEmployee.begin(), it);

        switch(sourceEmployee[index]->getStatus()) { // returning status

            case Intern::Status::Intern: // does it recognize object properly?

                auto tmp0 = std::move(*it);
                (*it).reset();                         // ??
                *it = std::make_shared<Worker>(tmp0);

                cout << "Employee " << id << " has been promoted" << endl;
                break;

【问题讨论】:

  • 在我看来,如果您对每个状态都有一个对象类型,并且另外将相关状态存储在每个对象类型中,那么您就是在复制信息。当您重复识别某些事物的方法时,您会引入它们可能不同步的可能性。
  • @Galik 我只是想要一些东西来区分对象。我认为最好使用enum class 而不是仅仅放置字段,即std::string status = "Intern",因为枚举更快。说到指针,我应该如何替换对象?
  • 您确定您正在解决正确的问题吗?看起来所有员工都应该直接由员工类表示,它只包含正确的信息。
  • 越来越好。现在有一个it 的声明。接下来:sourceEmployee 的声明(或将“Firm”更改为“sourceEmployee”)。另外需要考虑的一点:如果您使用从 ID 到员工的 std::map 而不是员工的 vector,则通过 ID 查找会更快。

标签: c++ object replace shared-ptr


【解决方案1】:

这就是我在您的示例中看到的。 Employee 与其派生类之间的唯一区别是派生类每个都有一个Status 字段。此字段在所有派生类中的用途相同。
问题:为什么要有派生类?只需让status 成为Employee 的一部分,并在员工升职和降职时为其分配适当的值。那么你的问题的答案是你只需为status 分配一个新值(大概是通过类方法)。

也许你忽略了关键细节。也许还有其他字段,所以有一个派生类的理由。
问题如果status对于类的所有对象都相同,为什么它不是@ 987654327@? (即便如此,感觉就像数据重复。可能有更好的方法来实现您的目标。)

如果要将一个派生类转换为另一个派生类,您可能需要为每个派生类定义一个构造函数,该构造函数将基类的引用作为参数。这将调用基类上的复制构造函数,然后初始化新类的字段。 (如果基类中没有要复制的字段,那么您的数据组织得不好。)

Worker::Worker(const Employee & person) : Employee(person) {}

至于调用它,看起来您正在进行不必要的簿记,这可能会导致错误。但是,很难说,因为您的代码不完整。猜测周围的上下文,可能会出现以下情况:

it->reset(std::make_shared<Worker>(**it));

当然,这个语法是否正确取决于it 是如何声明的,以及it 是如何被赋值的(两者都没有出现在问题中)。


现在让我们继续改进您的数据组织。您可能会发现,与其从Employee 派生,不如从InternWorkerManager 派生出一个Job 类。然后Employee 可以有一个指向Job 的(智能)指针,您的工作相关数据将驻留在其中。作为一个好处,切换工作时不需要复印;只需删除旧的Job 对象并分配一个新对象。 (这可以看作是我提到的第一种情况的概括,其中status 被简单地分配了一个新值。)

【讨论】:

  • 谢谢,我更新了相关代码。"it" 正在寻找指定的员工,` auto it = std::find_if(sourceEmployee.begin(), sourceEmployee.end(), [&sourceEmployee, id](const auto &obj) { return obj->getID() == id; });` 是的,我希望每个类都派生自Employee(稍后将为它们添加一些专有字段)。我想识别switch() 中的每个班级,我认为声明enum class 会很好(有什么更好的方法?)。
  • @Taknie 更好的方法是不识别switch 中的每个类。如果您的代码需要知道您正在处理哪个派生类,那么您做错了什么。通过虚拟方法告诉班级该做什么。以面向对象的思维方式考虑您的解决方案,而不是微观管理思维方式。
  • 我不明白。我正在使用虚拟方法来检查我正在处理的派生类。你说这是错误的。我应该如何控制要操作的对象。我已删除 enum 并替换为简单的 static const int 以仅通过对象的唯一编号来区分对象。回到我的问题,我仍然没有找到如何替换对象的解决方案。我按照您的建议创建了一个复制构造函数,但在这里我被卡住了。 it-&gt;reset(std::make_shared&lt;Worker&gt;(**it)); 语法不起作用(没有匹配的函数可以调用)
  • @Taknie 您不应该使用虚拟方法来检查您正在处理的派生类。您应该使用虚拟方法,而不必担心您正在处理哪个派生类。在你调用虚函数的地方,代码不应该基于你正在处理的派生类。
  • 好的,我明白了。我会在it 上使用dynamic_cast 来代替
猜你喜欢
  • 2012-12-05
  • 2020-03-15
  • 2012-07-22
  • 1970-01-01
  • 2018-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-07
相关资源
最近更新 更多