C++ 如何使对象知道它在哪个容器中?

C++ 如何使对象知道它在哪个容器中?,c++,c++11,stl,containers,unordered-set,C++,C++11,Stl,Containers,Unordered Set,我需要一种方法来把各种各样的东西放在一起。每个项目一次只能在一个集合中。我还需要能够问的项目,它是在哪个设置。我有3个问题: 这是一个有效的实现吗 如果我将类拆分为多个头文件,因为每个类都需要另一个头文件,那么如何使用它 我可以在item类中使用引用而不是指向Manager的指针吗(因为我不喜欢指针) 类管理器{ 公众: 添加项目(项目和项目){ 项目。插入(&项目); item.manager=这个; } 删除项目(项目和项目){ 项。删除(&item); item.manager=nullp

我需要一种方法来把各种各样的东西放在一起。每个项目一次只能在一个集合中。我还需要能够问的项目,它是在哪个设置。我有3个问题:

这是一个有效的实现吗

如果我将类拆分为多个头文件,因为每个类都需要另一个头文件,那么如何使用它

我可以在item类中使用引用而不是指向Manager的指针吗(因为我不喜欢指针)

类管理器{
公众:
添加项目(项目和项目){
项目。插入(&项目);
item.manager=这个;
}
删除项目(项目和项目){
项。删除(&item);
item.manager=nullptr;
}
私人:
std::无序的集合项目;
}
类项目{
公众:
管理器*获取管理器(){return Manager;}
私人:
经理*经理;
}
这是一个有效的实现吗?如果我拆分了文件,如何使用它 类转换为多个头文件,因为每个类都需要 其他的

您应该使用前向声明

在一个好的面向对象设计中,你的对象不应该知道它是如何存储的。看起来您的对象不应该负责需要本地化对象的活动

std::unordered_list<Item*> items; 
std::无序列表项;
这是不恰当的。是否要散列对象的地址

我可以在item类中使用引用而不是指向Manager的指针吗 (因为我不喜欢指针)


传递给函数时,始终可以用引用替换指针。这没有问题。

假设
管理者不希望拥有
项目
s,并且您对
项目
s和
管理者
的寿命都有一个清晰的概念,那么这似乎是合理的

如果要将类拆分为单独的头文件
Item.h
,只需向前声明
Manager
。事实上,就目前情况而言,
根本不需要对
管理器
进行完整的定义,因此您可以将其结构简化为:

项目.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
};
#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;
};
Manager.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
};
#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;
};
#包括“Item.h”
#包括
班级经理{
公众:
无效添加项目(项目和项目){
if(item.get_manager())
return;//项只能有一个管理器
项目。插入(&项目);
项目。设置管理器(本);
}
作废删除项目(项目和项目){
项。删除(&item);
项目设置管理器(空PTR);
}
私人:
std::无序的集合项目;
};

至于不喜欢指针,如果您想要一个可能为null的非所有者引用,那么指针是非常合适的。指针通常比成员变量的引用更合适,因为引用极大地限制了您对类的操作

如何让对象知道它在哪个容器中?

在适当的类设计中,您不应该这样做。有些事情是这样的,但我认为这超出了你的实际需要

这是一个有效的实现吗

没有

如果我将类拆分为多个头文件,因为每个类都需要另一个头文件,那么如何使用它

使用转发声明(查看更多详细信息)

我可以在item类中使用引用而不是指向Manager的指针吗(因为我不喜欢指针)

不,你不能


除了您实际提出的问题之外,更深入的是,它最终似乎是一个设计问题,您提出的是XY问题

你不喜欢(原始)指针是一种很好的直觉,你的实际设计可能有什么问题。很遗憾,您无法使用标准容器(如
std::unordered_set
)管理引用

不过,您可以使用设施提供的智能指针

您必须做出的主要决定是,在诸如
std::shared_pointer
std::weak_ptr
std::unique_ptr
等各种智能指针中,哪一个是管理必要的所有权要求的正确指针

另外,
Manager
可能不是您想要做的事情的最佳命名选择。如果有更好的东西适合这些,请查找经典

例如,听起来您需要一个类似,跟踪大量
项目
更改/事件,并将这些更改/事件转发给其他注册的
项目
实例的东西

由于
Observer
不需要拥有任何已注册
项目
实例的所有权,因此
std::weak_ptr
似乎是引用其中任何一个实例的正确选择

我需要一种方法来把各种各样的东西放在一起。每个项目一次只能在一个集合中。我还需要能够问的项目,它是在哪个设置。我有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;
}
如果我将类拆分为多个头文件,因为每个类都需要另一个头文件,那么如何使用它

你为什么要这么做?这些类似乎太简单了,没有任何必要,而且它只会使事情变得复杂。(正确的方法是使用前向声明标题。)

我可以在item类中使用引用而不是指向Manager的指针吗(因为我不喜欢指针)

不适用于当前的设计,因为在从
管理器
中删除
后,您的代码将
项.Manager
设置为
nullptr
,这是合理的做法

更一般地说,您确实需要确保实际的
对象的生命周期跨越在
管理器
对象中存储指向它们的指针的时间。这可能是也可能不是代码编写方式的自然结果,或者通过调用
item.manager->remove(item)轻松实现
项之前
'