我需要一种方法将各种物品放入套装中。每个项目一次只能设置1个。我还需要能够询问项目所在的项目。我有3个问题:
这是有效的实施吗?
如果我将类拆分成多个头文件,我怎么能使用它,因为每个类需要另一个?
我可以在项目类中使用引用而不是指向Manager的指针(因为我不喜欢指针)吗?
class Manager {
public:
add_item(Item& item) {
items.insert(&item);
item.manager = this;
}
remove_item(Item& item) {
items.erase(&item);
item.manager = nullptr;
}
private:
std::unordered_set<Item*> items;
}
class Item {
public:
Manager* get_manager() {return manager;}
private:
Manager* manager;
}
答案 0 :(得分:1)
这是有效的实施吗?如果我拆分,我该如何使用它 将类分成多个头文件,因为每个类都需要 其他
你应该使用前向声明。
在良好的面向对象设计中,您的对象不应该知道它是如何存储的。看起来您的对象不应该对需要本地化对象的活动负责。
std::unordered_list<Item*> items;
这不合适。您想要散列对象的地址吗?
我可以在项目类中使用引用而不是指向Manager的指针 (因为我不喜欢指针)?
传递给函数时总是可以用引用替换指针。它没有问题。
答案 1 :(得分:1)
如何让对象知道它所在的容器?
你不应该在适当的班级设计中这样做。有Dependency Injection之类的东西,但我认为这超出了你的实际需要。
这是一个有效的实施吗?
没有
如果我将类拆分成多个头文件,我怎么能使用它,因为每个类需要另一个?
使用前向声明(有关详细信息,请查看here)。
我可以在项目类中使用引用而不是指向Manager的指针(因为我不喜欢指针)吗?
不,你不能。
除了实际问题之外,还有更深入的问题,它最终似乎是一个设计问题,而且你要求XY问题。
你不喜欢(原始)指针是一种非常好的胆量感觉,你的实际设计可能有什么问题。好吧,遗憾的是,您无法使用std::unordered_set
等标准容器管理引用。
你可以做的是使用Dynamic memory management设施提供的智能指针。
您必须采取的主要决策是,std::shared_pointer
,std::weak_ptr
或std::unique_ptr
等各种智能指针是管理必要 所有权的正确指针之一要求 语义正确。
同样Manager
可能不是您想要做的最佳命名选择。请查看经典Design Patterns,如果有更合适的东西。
例如,您需要Observer之类的内容来跟踪多个Item
更改/事件,并将这些内容转发给其他已注册的Item
实例。
由于Observer
不需要拥有任何已注册Item
个实例的所有权,因此std::weak_ptr
似乎是引用任何实例的正确选择。
答案 2 :(得分:1)
我需要一种方法将各种物品放入套装中。每个项目一次只能设置1个。我还需要能够询问项目所在的项目。我有3个问题:
这是一个有效的实施吗?
基本思想是合理的,但它不会强制执行您的数据模型或防范有问题的场景。有关您可以做的事情的示例:
void add_item(Item& item) {
if (item.manager == this) return; // already owner
if (item.manager) // already has another owner...
item.manager->remove(item);
items.insert(&item);
item.manager = this;
}
如果我将类拆分成多个头文件,我怎么能使用它,因为每个类需要另一个?
你为什么要这样?这些类似乎太简单了,没有任何需要,它只会让事情复杂化。 (正确的方法是使用前向声明标题。)
我可以在项目类中使用引用而不是指向Manager的指针(因为我不喜欢指针)吗?
不符合您当前的设计,因为从item.Manager
移除nullptr
后,您的代码会将Item
设置为Manager
,这是合理的做法。
更一般地说,您需要确保实际Item
个对象的生命周期跨越您在Manager
对象中存储指针的时间。这可能是也可能不是代码编写方式的自然结果,或者通过在item.manager->remove(item);
销毁之前调用Item
轻松实现。
答案 3 :(得分:0)
假设不期望Manager
拥有Item
并且你清楚地知道Item
和Manager
的生命周期,那么这似乎是合理的
如果要将类拆分为单独的头文件Item.h
,只需要Manager
的前向声明。实际上,Item
根本不需要Manager
的完整定义,因此您可以将其简化为:
<强> Item.h 强>
class Manager; // forward declaration
class Item {
public:
Manager* get_manager() const { return manager; }
void set_manager(Manager* new_manager) { manager = new_manager; }
private:
Manager* manager = nullptr; // Ensure initialized to null
};
<强> Manager.h 强>
#include "Item.h"
#include <unordered_set>
class Manager {
public:
void add_item(Item& item) {
if (item.get_manager())
return; // Item can have only one Manager
items.insert(&item);
item.set_manager(this);
}
void remove_item(Item& item) {
items.erase(&item);
item.set_manager(nullptr);
}
private:
std::unordered_set<Item*> items;
};
至于不喜欢指针,如果你想要一个可以为null的非拥有引用,那么指针是一个非常合适的选择。指针通常比成员变量的引用更合适,因为引用限制了您可以对类进行的操作。