C++ 关系,即;继承;另一(1:N)关系
我想要一个支持这些特定1:N关系的数据结构:-C++ 关系,即;继承;另一(1:N)关系,c++,design-patterns,data-structures,game-engine,one-to-many,C++,Design Patterns,Data Structures,Game Engine,One To Many,我想要一个支持这些特定1:N关系的数据结构:- 1#. 人类提升0-N人类 2#. 人类拥有0-N狗 3#. 人类培养0-N树 4#. Dog是一个0-N寄生虫的家 注意: -这些关系中的状态都是暂时的,例如,Human1可能提高Human2,但一年后,Human1可能放弃Human2 -所有对象都继承自BaseObject,并且具有唯一的int-ID 在所有上述关系中,我希望能够支持这些功能:- F1。添加关系,例如human\u dog->addRelation(human*a,dog*b
1#. <代码>人类提升0-N
人类
2#. <代码>人类拥有0-N
狗
3#. <代码>人类培养0-N
树
4#.
Dog
是一个0-N寄生虫的家
注意:
-这些关系中的状态都是暂时的,例如,Human1
可能提高Human2
,但一年后,Human1
可能放弃Human2
-所有对象都继承自BaseObject
,并且具有唯一的int-ID
在所有上述关系中,我希望能够支持这些功能:-
F1。添加关系,例如human\u dog->addRelation(human*a,dog*b)
F2。删除关系,例如人狗->删除关系(人*a,狗*b)
F3。查询所有子项,例如human\u dog->getAllChildren(human*)
F4。查询所有父母,例如人狗->获取所有父母(狗*)
F5。检查父项是否有>=1个子项
F6。检查子项是否有>=1个父项
F7。删除父级的所有子级
F8。删除子级的所有父级
这可以通过std::unordered_map
或更容易定制的东西来实现
困难的部分来了
我想将关系1、2、3(即所有实线)标记为馈送
它必须以聚合方式支持功能F3-F8
例如:
feed->getAllChildren(BaseObject*b)
:
如果b
是人类,则必须返回b
的抚养、拥有和培育的所有子女李>
feed->removeAllParent(BaseObject*b)
:
如果b
是一只狗,它的效果就像trave->removeAllParent(b)
总之,我希望能够轻松地注入这样的聚合
例如,可以调用:-
void BaseObject::declareForFreedom(){
feed->removeAllParent(this);
}
上面的示例仅显示4个关系和1个间接级别。
在我的真实案例中,这种继承/间接有8-10个关系和3-4个级别
问题:
适合这种情况的数据结构/设计模式是什么
我目前为1#-4#创建了一个自定义的1:N关系,并对每个提要的函数进行硬编码。这很乏味。
几个月来,我一直在绞尽脑汁,但没有发现任何看起来优雅的实现
演示
基本类型:-
#include <iostream>
#include <map>
#include <vector>
enum class Type{
HUMAN,DOG,TREE,PARASITE,ERROR
}; //for simplicity
class BaseObject{public: Type type=Type::ERROR; };
class Human : public BaseObject{
public: Human(){ type=Type::HUMAN; }
};
class Dog : public BaseObject{
public: Dog(){ type=Type::DOG; }
};
class Tree : public BaseObject{
public: Tree(){ type=Type::TREE; }
};
class Parasite : public BaseObject{
public: Parasite(){ type=Type::PARASITE; }
};
#包括
#包括
#包括
枚举类类型{
人、狗、树、寄生虫、错误
}; //为了简单起见
类BaseObject{public:Type=Type::ERROR;};
类Human:publicbaseObject{
public:Human(){type=type::Human;}
};
类Dog:公共基对象{
public:Dog(){type=type::Dog;}
};
类树:公共基对象{
public:Tree(){type=type::Tree;}
};
类寄生虫:公共基对象{
public:寄生虫(){type=type::寄生虫;}
};
基本1:N映射
template<class A,class B> class MapSimple{
std::multimap<A*, B*> aToB;
std::multimap<B*, A*> bToA;
public: void addRelation(A* b1,B* b2){
aToB.insert ( std::pair<A*,B*>(b1,b2) );
bToA.insert ( std::pair<B*,A*>(b2,b1) );
}
public: std::vector<B*> queryAllChildren(A* b1){
auto ret = aToB.equal_range(b1);
auto result=std::vector<B*>();
for (auto it=ret.first; it!=ret.second; ++it){
result.push_back(it->second);
}
return result;
}
public: void removeAllParent(B* b){
if(bToA.count(b)==0)return;
A* a=bToA.find(b)->second;
bToA.erase(b);
auto iterpair = aToB.equal_range(a);
auto it = iterpair.first;
for (; it != iterpair.second; ++it) {
if (it->second == b) {
aToB.erase(it);
break;
}
}
}
//.. other functions
};
模板类MapSimple{
std::多映射aToB;
std::multimap-bToA;
公共:无效添加关系(A*b1,B*b2){
aToB.insert(std::pair(b1,b2));
bToA.insert(std::pair(b2,b1));
}
公共:标准::矢量查询儿童(A*b1){
自动恢复=自动平衡范围(b1);
自动结果=标准::向量();
用于(自动it=ret.first;it!=ret.second;++it){
结果:向后推(它->秒);
}
返回结果;
}
public:void removeAllParent(B*B){
if(bToA.count(b)==0)返回;
A*A=bToA.find(b)->秒;
bToA.擦除(b);
自动iterpair=aToB.equal_范围(a);
auto it=iterpair.first;
for(;it!=iterpair.second;++it){
如果(it->second==b){
删除(它);
打破
}
}
}
//…其他功能
};
以下是数据库实例和聚合:-
MapSimple<Human,Human> raise;
MapSimple<Human,Dog> has;
MapSimple<Human,Tree> cultivate;
MapSimple<Dog,Parasite> isHouseOf;
class Feed{
public: void removeAllParent(BaseObject* b1){
if(b1->type==Type::HUMAN){
raise.removeAllParent(static_cast<Human*>(b1));
}
if(b1->type==Type::DOG){
has.removeAllParent(static_cast<Dog*>(b1));
}
//.... some other condition (I have to hard code them - tedious) ...
}
//other function
};
Feed feed;
map简单提升;
MapSimple有;
简单栽培;
MapSimple isHouseOf;
类提要{
public:void removeAllParent(BaseObject*b1){
如果(b1->type==type::HUMAN){
提升。移除所有父级(静态施法(b1));
}
如果(b1->type==type::DOG){
has.removeAllParent(static_cast(b1));
}
//…其他一些条件(我必须硬编码-乏味)。。。
}
//其他功能
};
饲料;
用法
intmain(){
人h1;
狗只d1、d2;
has.addRelation(&h1和&d1);
has.addRelation(&h1和&d2);
自动结果=has.queryalchildren(&h1);
std::cout直接实现有什么问题
例如:
BaseObject.hpp
#include <vector>
template<class T>
using prtVector = std::vector<T*>;
class BaseObject {
public:
virtual prtVector<BaseObject> getAllParents() const = 0;
virtual prtVector<BaseObject> getAllChilderen() const = 0;
virtual void removeAllParents() = 0;
virtual void removeAllChildren() = 0;
};
#包括
模板
使用prtVector=std::vector;
类基类对象{
公众:
虚拟prtVector getAllParents()常量=0;
虚拟prtVector getAllChildren()常量=0;
虚拟void removeAllParents()=0;
虚拟void removeAllChildren()=0;
};
人乳头状瘤
#include "BaseObject.hpp"
#include "Tree.hpp"
#include "Dog.hpp"
class Tree;
class Dog;
class Human : public BaseObject {
public:
prtVector<BaseObject> getAllParents() const override;
prtVector<BaseObject> getAllChildren() const override;
void removeAllParents() override;
void removeAllChildren() override ;
friend class Dog;
friend class Tree;
template<class A, class B>
friend void addRelation(A* a, B* b);
private:
void addParent(Human* const);
void removeParent(Human const* const);
void addChild(Human* const);
void removeChild(Human const* const);
void addChild(Tree* const);
void removeChild(Tree const* const);
void addChild(Dog* const);
void removeChild(Dog const* const);
private:
prtVector<Human> parents;
prtVector<Human> children;
prtVector<Tree> plants;
prtVector<Dog> pets;
};
#包括“BaseObject.hpp”
#包括“Tree.hpp”
#包括“Dog.hpp”
类树;
班犬;
类Human:publicbaseObject{
公众:
prtVector getAllParents()常量重写;
prtVector getAllChildren()常量覆盖;
void removeAllParents()覆盖;
void removeAllChildren()覆盖;
朋友级狗;
朋友类树;
模板
朋友关系(A*A,B*B);
私人:
void addParent(人类*常量);
void removeParent(人类常量*常量);
void addChild(人类*const);
void removeChild(人类常量*常量);
void addChild(树*const);
void removeChild(树常数*常数);
void addChild(Dog*const);
void removeChild(狗常数*常数);
私人:
家长;
普特维特儿童;
植物;
prtVector宠物
#include "BaseObject.hpp"
#include "Tree.hpp"
#include "Dog.hpp"
class Tree;
class Dog;
class Human : public BaseObject {
public:
prtVector<BaseObject> getAllParents() const override;
prtVector<BaseObject> getAllChildren() const override;
void removeAllParents() override;
void removeAllChildren() override ;
friend class Dog;
friend class Tree;
template<class A, class B>
friend void addRelation(A* a, B* b);
private:
void addParent(Human* const);
void removeParent(Human const* const);
void addChild(Human* const);
void removeChild(Human const* const);
void addChild(Tree* const);
void removeChild(Tree const* const);
void addChild(Dog* const);
void removeChild(Dog const* const);
private:
prtVector<Human> parents;
prtVector<Human> children;
prtVector<Tree> plants;
prtVector<Dog> pets;
};
#include "Human.hpp"
prtVector<BaseObject> Human::getAllParents() const {
prtVector<BaseObject> result(std::cbegin(parents), std::cend(parents));
return result;
}
prtVector<BaseObject> Human::getAllChildren() const {
prtVector<BaseObject> result(std::cbegin(children), std::cend(children));
result.insert(std::end(result), std::cbegin(pets), std::cend(pets));
result.insert(std::end(result), std::cbegin(plants), std::cend(plants));
return result;
}
void Human::removeAllParents() {
for (auto parent : parents) { parent->removeChild(this); }
parents.clear();
}
void Human::removeAllChildren() {
for (auto child : children) { child->removeParent(this); } children.clear();
for (auto pet : pets) { pet->removeParent(this); } pets.clear();
for (auto plant : plants) { plant->removeParent(this); } plants.clear();
}
void Human::addParent(Human* const parent) { parents.push_back(parent); }
#include <algorithm>
void Human::removeParent(Human const* const parent) {
auto it = std::find(std::cbegin(parents), std::cend(parents), parent);
if (it != std::cend(parents)) parents.erase(it);
}
void Human::addChild(Human* const child) { children.push_back(child); }
#include "Human.hpp"
#include "Dog.hpp"
template<class A, class B>
void addRelation(A* a, B* b)
{
a->addChild(b);
b->addParent(a);
}
template<class A>
prtVector<BaseObject> queryAllChildren(A* obj)
{
return obj->getAllChilderen();
}
template<class A>
void removeAllParents(A* obj)
{
obj->removeAllParents();
}
#include <iostream>
int main() {
Human h1;
Dog d1, d2;
addRelation(&h1, &d1);
addRelation(&h1, &d2);
auto result = queryAllChildren(&h1);
std::cout << result.size() << "\n"; //print 2
removeAllParents(&d1);
result = queryAllChildren(&h1);
std::cout << result.size() << "\n"; //print 1
std::cin.ignore();
}
#include <algorithm>
#include <tuple>
#include <vector>
class BaseObject {
public:
virtual ~BaseObject() = default;
virtual std::vector<BaseObject*> getAllParents() const = 0;
virtual std::vector<BaseObject*> getAllChildren() const = 0;
virtual void removeAllParents() = 0;
virtual void removeAllChildren() = 0;
};
template<typename TParentTuple, typename TChilderenTuple>
class Obj;
template<typename... ParentTags,
typename... ChildTags>
class Obj<std::tuple<ParentTags...>, std::tuple<ChildTags...>> : public BaseObject
{
std::tuple<std::vector<typename ParentTags::obj_type*>...> parents;
std::tuple<std::vector<typename ChildTags::obj_type*>...> children;
public:
template <typename T>
void addParent(T* parent) { std::get<std::vector<T*>>(parents).push_back(parent); }
template <typename T>
void removeParent(const T* parent) {
auto& v = std::get<std::vector<T*>>(parents);
auto it = std::find(std::cbegin(v), std::cend(v), parent);
if (it != std::cend(v)) { v.erase(it); }
}
template <typename T>
void addChild(T* child) { std::get<std::vector<T*>>(children).push_back(child); }
template <typename T>
void removeChild(const T* child) {
auto& v = std::get<std::vector<T*>>(children);
auto it = std::find(std::cbegin(v), std::cend(v), child);
if (it != std::cend(v)) { v.erase(it); }
}
std::vector<BaseObject*> getAllParents() const override {
std::vector<BaseObject*> res;
std::apply([&](auto&... v){ (res.insert(res.end(), v.begin(), v.end()), ...); },
parents);
return res;
}
std::vector<BaseObject*> getAllChildren() const override {
std::vector<BaseObject*> res;
std::apply([&](auto&... v){ (res.insert(res.end(), v.begin(), v.end()), ...); },
children);
return res;
}
void removeAllParents() override {
std::apply(
[this](auto&... v)
{
[[maybe_unused]] auto clean = [this](auto& v) {
for (auto* parent : v) {
parent->removeChild(this);
}
v.clear();
};
(clean(v), ...);
},
parents);
}
void removeAllChildren() override {
std::apply(
[this](auto&... v)
{
[[maybe_unused]] auto clean = [this](auto& v) {
for (auto* child : v) {
child->removeParent(this);
}
v.clear();
};
( clean(v), ...);
},
children);
}
};
struct Human_tag;
struct Tree_tag;
struct Dog_tag;
struct Parasite_tag;
using Human = Obj<std::tuple<>, std::tuple<Tree_tag, Dog_tag>>;
using Tree = Obj<std::tuple<Human_tag>, std::tuple<>>;
using Dog = Obj<std::tuple<Human_tag>, std::tuple<Parasite_tag>>;
using Parasite = Obj<std::tuple<Dog_tag>, std::tuple<>>;
struct Human_tag { using obj_type = Human; };
struct Tree_tag { using obj_type = Tree; };
struct Dog_tag { using obj_type = Dog; };
struct Parasite_tag { using obj_type = Parasite; };
template<class A, class B>
void addRelation(A* a, B* b)
{
a->addChild(b);
b->addParent(a);
}
#include <iostream>
int main() {
Human h1;
Dog d1, d2;
addRelation(&h1, &d1);
addRelation(&h1, &d2);
auto result = h1.getAllChildren();
std::cout << result.size() << "\n"; //print 2
d1.removeAllParents();
result = h1.getAllChildren();
std::cout << result.size() << "\n"; //print 1
}
#include <tuple>
#include <vector>
#include <algorithm>
template<class T>
using prtVector = std::vector<T*>;
// Interface, as required by assignment
class BaseObject {
public:
virtual ~BaseObject() {}
virtual prtVector<BaseObject> getAllParents() const = 0;
virtual prtVector<BaseObject> getAllChildren() const = 0;
virtual void removeAllParents() = 0;
virtual void removeAllChildren() = 0;
};
// base prototype
template<typename TOwnTag, typename TParentTagsTuple, typename TChildTagsTuple>
class Obj;
// Parent-type deduction
template<typename TOwnTag, typename TParentTag, typename... TParentTags, typename... TChildTags>
class Obj<TOwnTag, std::tuple<TParentTag, TParentTags...>, std::tuple<TChildTags...>>
: public Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>
{
// local types
using TOwn = typename TOwnTag::obj_type;
using TParent = typename TParentTag::obj_type;
// container
prtVector<TParent> parentsPtrs;
//befriend types
friend class Obj;
template<class A, class B>
friend void addRelation(A* const a, B* const b);
protected:
// prevent base function hiding with 'using'-declaration
using Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::addParent;
using Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::removeParent;
// add and remove element functions
void addParent(TParent* const parentPtr) { parentsPtrs.push_back(parentPtr); }
void removeParent(TParent const* const parentPtr) {
auto it = std::find(std::cbegin(parentsPtrs), std::cend(parentsPtrs), parentPtr);
if (it != std::cend(parentsPtrs)) parentsPtrs.erase(it);
}
public:
virtual ~Obj() {}
virtual prtVector<BaseObject> getAllParents() const override {
auto result = Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::getAllParents();
result.insert(std::begin(result), std::cbegin(parentsPtrs), std::cend(parentsPtrs));
return result;
}
virtual prtVector<BaseObject> getAllChildren() const override {
return Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::getAllChildren();
}
virtual void removeAllParents() override {
Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::removeAllParents();
for (auto&& parent : parentsPtrs) parent->removeChild(reinterpret_cast<TOwn* const>(this));
}
virtual void removeAllChildren() override {
Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::removeAllChildren();
}
};
// Child-type deduction
template<typename TOwnTag, typename TChildTag, typename... TChildTags>
class Obj<TOwnTag, std::tuple<>, std::tuple<TChildTag, TChildTags...>>
: public Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>
{
// local types
using TOwn = typename TOwnTag::obj_type;
using TChild = typename TChildTag::obj_type;
// container
prtVector<TChild> childrenPtrs;
//befriend types
friend class Obj;
template<class A, class B>
friend void addRelation(A* const a, B* const b);
protected:
// empty functions required for 'using'-declaration
void addParent() {}
void removeParent() {}
// prevent base function hiding with 'using'-declaration
using Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>::addChild;
using Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>::removeChild;
// add and remove element functions
void addChild(TChild* const childPtr) { childrenPtrs.push_back(childPtr); }
void removeChild(TChild const* const childPtr) {
auto it = std::find(std::cbegin(childrenPtrs), std::cend(childrenPtrs), childPtr);
if (it != std::cend(childrenPtrs)) childrenPtrs.erase(it);
}
public:
virtual ~Obj() {}
virtual prtVector<BaseObject> getAllParents() const override {
return Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>::getAllParents();
}
virtual prtVector<BaseObject> getAllChildren() const override {
auto result = Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>::getAllChildren();
result.insert(std::begin(result), std::cbegin(childrenPtrs), std::cend(childrenPtrs));
return result;
}
virtual void removeAllParents() override {}
virtual void removeAllChildren() override {
Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>::removeAllChildren();
for (auto&& child : childrenPtrs) child->removeParent(reinterpret_cast<TOwn* const>(this));
}
};
// terminator
template<typename TOwnTag>
class Obj<TOwnTag, std::tuple<>, std::tuple<>> : public BaseObject {
protected:
// empty functions required for 'using'-declaration
void addChild() {}
void removeChild() {}
void addParent() {}
void removeParent() {}
public:
virtual ~Obj() {}
virtual prtVector<BaseObject> getAllParents() const override {
return prtVector<BaseObject>();
}
virtual prtVector<BaseObject> getAllChildren() const override {
return prtVector<BaseObject>();
}
virtual void removeAllParents() override {}
virtual void removeAllChildren() override {}
};
//prototype class tags
struct Human_tag;
struct Tree_tag;
struct Dog_tag;
struct Parasite_tag;
//define class types
using Human = Obj<Human_tag, std::tuple<>, std::tuple<Tree_tag, Dog_tag>>;
using Tree = Obj<Tree_tag, std::tuple<Human_tag>, std::tuple<>>;
using Dog = Obj<Dog_tag, std::tuple<Human_tag>, std::tuple<Parasite_tag>>;
using Parasite = Obj<Parasite_tag, std::tuple<Dog_tag>, std::tuple<>>;
//couple tags to classes
struct Human_tag { using obj_type = Human; };
struct Tree_tag { using obj_type = Tree; };
struct Dog_tag { using obj_type = Dog; };
struct Parasite_tag { using obj_type = Parasite; };
//(befriend)helper function
// maybe could do somehting with std::enable_if
// i.e. "enable if type B is in child tuple of A and
// type A is in parent tuple of B"
// that way the parser will already detect a relation is not possible
template<class A, class B>
void addRelation(A* const a, B* const b)
{
a->addChild(b);
b->addParent(a);
}
// now for some testing
#include <iostream>
int main() {
Human h1;
Dog d1, d2;
Parasite p1;
addRelation(&h1, &d1);
addRelation(&h1, &d2);
addRelation(&d1, &p1);
//addRelation(&h1, &p1); // compiler error
auto result = h1.getAllChildren();
std::cout << result.size() << "\n"; //print 2
d1.removeAllParents();
result = h1.getAllChildren();
std::cout << result.size() << "\n"; //print 1
std::cin.ignore();
}