C++ 如何在C+;中创建自动键值工厂模式+;?
我的确切问题有点难以解释,因此这里有一个简化版本: 我有各种类型的动物(模块)和庇护所(模块管理员)。这些包括狗、猫和鸟。主人(父母)可以调用收容所的函数,其中包括他想要收养的动物类型的字符串和使动物生活更轻松的通用项目(参考)列表。物品清单是可变的,但必须包括特定动物所需的所有且仅包括所需物品,因动物而异(狗需要项圈和皮带,猫需要一棵香蒲和一个垃圾箱,鸟需要一个笼子等)。该列表还包括对所有者的引用,以便动物知道它属于谁 基本上它应该是这样的:C++ 如何在C+;中创建自动键值工厂模式+;?,c++,inheritance,module,C++,Inheritance,Module,我的确切问题有点难以解释,因此这里有一个简化版本: 我有各种类型的动物(模块)和庇护所(模块管理员)。这些包括狗、猫和鸟。主人(父母)可以调用收容所的函数,其中包括他想要收养的动物类型的字符串和使动物生活更轻松的通用项目(参考)列表。物品清单是可变的,但必须包括特定动物所需的所有且仅包括所需物品,因动物而异(狗需要项圈和皮带,猫需要一棵香蒲和一个垃圾箱,鸟需要一个笼子等)。该列表还包括对所有者的引用,以便动物知道它属于谁 基本上它应该是这样的: Animal * getAnimal(String
Animal * getAnimal(String name, void * Items, int size_items)
//From Customer Class
Parrot * lester=dynamic_cast<Parrot*>(getAnimal("parrot", [this, new Cage()]))
Parrot(void * items)
稍后,程序员可以通过调用
addAnimal(String Key, Class type)
我希望这能准确地解释我的问题。基本上,我需要一种创建父类的标准化子类的方法,在这种方法中,用户可以添加更多的子类,而无需回到经典
if x=="Parrot" then return new Parrot(a)
如果它们都是从基类派生的,那么可以使用工厂模式,例如from(注意,这本书是C++11之前的版本,但是这个答案会为更现代的编译器更新它) 下面创建一些具体的动物并将它们放入向量中,然后对每个动物调用
eat()
方法:
#include <memory>
#include <iostream>
#include "factory.h"
struct Animal
{
virtual ~Animal() = default;
virtual void eat() = 0;
};
struct Cat : Animal
{
static constexpr auto ID = 1;
explicit Cat( const void* ) { }
void eat() override { std::cout << "Mice\n"; }
};
struct Parrot : Animal
{
static constexpr auto ID = 2;
explicit Parrot( const void* ) { }
void eat() override { std::cout << "Crackers\n"; }
struct Data
{
double age;
std::string name;
};
};
// Create the factory object
auto g_factory = MyUtil::Factory<std::unique_ptr<Animal>, int, std::function<std::unique_ptr<Animal>(const void*)>>{};
void RegisterTypesWithFactory()
{
// Map an ID to a creator function in the factory
g_factory.Register( Cat::ID, []( const void* data ) { return std::make_unique<Cat>( data ); } );
g_factory.Register( Parrot::ID, []( const void* data ) { return std::make_unique<Parrot>( data ); } );
}
int main()
{
// Configure the factory
// Note: Registration can be done any time, e.g., later based on input
// from a file. I do them all at once here for convenience of illustration.
RegisterTypesWithFactory();
// Arbitrary initialization data of differing types
// (to be passed as opaque data to ctors with void* or std::any)
const auto catData = { 1, 2, 3 };
const auto birdData = Parrot::Data{ 5.6, "polly" };
// Create some objects with the factory
auto animals = std::vector<std::unique_ptr<Animal>>{};
animals.emplace_back( g_factory.Create( Cat::ID, &catData ) );
animals.emplace_back( g_factory.Create( Parrot::ID, &birdData ) );
// Do something with the objects
for( const auto& a : animals )
{
a->eat();
}
}
看它在现场运行
,在C++ >代码> VUL**/COD>不赞成。合适的替代品可能是(或者如果您缺少C++17)。
如评论中所述,您似乎正在寻找一个框架,用于将派生类型注册到工厂调度中。这实际上是一种非常流行的模式,在堆栈溢出(例如)中存在许多类似的问题(和答案) 中介绍了从头开始的更逐步的实现,这反过来又受到了堆栈溢出的启发 当然,使用boost的优点是很多东西已经实现了,因此隐藏在主代码之外。缺点是,首先您需要依赖boost,其次,没有经验的程序员可能会发现它令人困惑。看起来像是没有使用boost的更详细解释的翻版:Thank seams Usefull我不理解您希望用户在运行时创建新的动物,例如dog(),dog是一个新的类,它继承自动物,但您没有实现它?我总是对常见的OOP示例(如动物)感到困惑。制作一个家长级的动物和孩子级的动物,比如狗或鹦鹉,对我来说意义不大。它们之间没有足够的共性,而且闻起来像Java的“对象”。C++不是这样,接缝有点复杂,但在说车辆时,它不应该说动物吗?我不明白这行代码的作用:g_factory.Register(Cat::ID,&std::make_unique);g_工厂寄存器(Parrot::ID和std::make_unique)@user1510024对不起,我根据之前的回答改编了这个。我现在已经更新了它,并链接到它在Wandbox上运行。对
Register()
的调用动态地(即在运行时)设置工厂,这意味着您只能根据避难所基于用户输入或文件提供的内容来填充工厂。因此,您基本上可以将函数保存在一个键值对中,该键值对依次获取动物属性,然后返回动物实例?@user1510024 Yes。Wandbox链接有factory.h的源代码,它是从Loki的C++03版本更新而来的。@user1510024您还可以半自动化注册过程。请参阅以了解有关如何执行此操作的更多信息。我会在这里做的,但我看到你已经选择了答案,所以你削弱了我的动力
Mice
Crackers