c++ 如何创建一个包含多个类的类工厂,这些类具有不同的参数,但返回类型相同?

mzmfm0qo  于 2024-01-09  发布在  其他
关注(0)|答案(1)|浏览(192)

我在这里问这个问题是想从一个真实的人的Angular 来听。
我想创建一个具有以下签名的类工厂:

  1. Component* (GameObject*, ...)

字符串
在某些情况下,这是我的ProximentFactory类:

.h

  1. #pragma once
  2. // Dependencies | std
  3. #include <functional>
  4. #include <vector>
  5. #include <utility>
  6. // Dependencies | CoreEngine
  7. #include "Component.h"
  8. #include "GameObject.h"
  9. class ComponentFactory {
  10. // Object
  11. public:
  12. // Properties
  13. std::vector<std::pair<const type_info*, std::function<Component* (GameObject* gameObject)>>> factory = std::vector<std::pair<const type_info*, std::function<Component* (GameObject*)>>>();
  14. // Constructor / Destructor
  15. ComponentFactory();
  16. ~ComponentFactory();
  17. // Functions
  18. void addRegistry(const type_info* typeInfo, std::function<Component* (GameObject*)> contructor);
  19. Component* create(GameObject* gameObject, const type_info* typeInfo);
  20. };

.cpp

  1. #include "ComponentFactory.h"
  2. // class ComponentFactory
  3. // Object | public
  4. // Constructor / Destructor
  5. ComponentFactory::ComponentFactory() {
  6. }
  7. ComponentFactory::~ComponentFactory() {
  8. }
  9. // Functions
  10. void ComponentFactory::addRegistry(const type_info* typeInfo, std::function<Component* (GameObject*)> constructor) {
  11. std::pair<const type_info*, std::function<Component* (GameObject*)>> registry = std::pair<const type_info*, std::function<Component* (GameObject*)>>(typeInfo, constructor);
  12. factory.push_back(registry);
  13. }
  14. Component* ComponentFactory::create(GameObject* gameObject, const type_info* typeInfo) {
  15. for (const std::pair<const type_info*, std::function<Component* (GameObject*)>>& registry : factory)
  16. if (registry.first == typeInfo)
  17. return registry.second(gameObject);
  18. return nullptr;
  19. }


我的代码的问题是,某些组件不仅仅接受GameObject*作为参数。它需要能够返回Component*,第一个参数必须是GameObject*,从那里开始,任何其他参数和任何数量的参数。例如:

  1. Component* (GameObject*, ...)


目标是向组件工厂传递const type_info*GameObject及其参数,并获得Component*指针作为结果。
注意事项:我的组件工厂必须是一个对象,因为我需要不同的组件工厂,并且我试图用更大的代码构建has a关系。
注意:Component是其他类派生的类。
注意:每个Component对象都有一个cont type_info* typeInfo变量,它的子对象也有。
最后,它应该看起来像这样:

  1. componentFactory.create(gameObject, *typeid(someClass), ...)


下面是一个我正在阅读的JSON示例,正如在评论部分中所要求的那样。一旦它被读取,我就会尝试创建其中指定的对象。正如你所看到的,type_info.name()在文件中保存为type。我将其与组件工厂中存储的type_info进行匹配。

  1. {
  2. "gameObjects": [
  3. {
  4. "id": 1,
  5. "name": "Camera Game Object",
  6. "transform": {
  7. "position": [
  8. 0.0,
  9. 0.0,
  10. 0.0
  11. ],
  12. "rotation": [
  13. 0.0,
  14. 0.0,
  15. 0.0
  16. ],
  17. "scale": [
  18. 1.0,
  19. 1.0,
  20. 1.0
  21. ]
  22. }
  23. }
  24. ],
  25. "transformRelationships": null,
  26. "components": [
  27. {
  28. "gameObjectIndex": 0,
  29. "type": "class Camera2D",
  30. "data": {
  31. "graphicsContextIndex": 0,
  32. "viewSize": 16.0,
  33. "backgroundColor": [
  34. 0.15000000596046448,
  35. 0.15000000596046448,
  36. 0.15000000596046448,
  37. 1.0
  38. ]
  39. }
  40. },
  41. {
  42. "gameObjectIndex": 0,
  43. "type": "class CameraController",
  44. "data": {
  45. "stength": 1.0
  46. }
  47. },
  48. {
  49. "gameObjectIndex": 0,
  50. "type": "class GameObjectController",
  51. "data": {
  52. "strenght": 0.10000000149011612
  53. }
  54. },
  55. {
  56. "gameObjectIndex": 0,
  57. "type": "class EmptyComponent",
  58. "data": {}
  59. }
  60. ]
  61. }

2mbi3lxu

2mbi3lxu1#

我使用了两个Component,并假设一个类似于下面的实现:

  1. namespace ns { // your namespace
  2. struct Component {
  3. virtual ~Component() = default;
  4. };
  5. struct Camera2D : Component {
  6. Camera2D(std::size_t graphicsContextIndex, double viewSize,
  7. const std::array<double, 4>& backgroundColor) :
  8. graphicsContextIndex(graphicsContextIndex),
  9. viewSize(viewSize),
  10. backgroundColor(backgroundColor)
  11. {}
  12. std::size_t graphicsContextIndex;
  13. double viewSize;
  14. std::array<double, 4> backgroundColor;
  15. };
  16. struct CameraController : Component {
  17. CameraController(double strength) : strength(strength) {}
  18. double strength;
  19. };

字符串
然后一个工厂,下面的componentFactory,可以简单地是一个函数,它有一个从类名到示例化该类的函数的Map。因为你想要Component*,而类可能继承自Component,这个工厂函数返回一个std::unique_ptr<Component>

  1. template<class T>
  2. std::unique_ptr<Component> getComponentPtr(const json& j) {
  3. // use the nlohmann::adl_serializer:
  4. return j.get<std::unique_ptr<T>>();
  5. }
  6. std::unique_ptr<Component> componentFactory(const json& j) {
  7. static const std::unordered_map<std::string_view,
  8. std::unique_ptr<Component>(*)(const json&)>
  9. functions{
  10. {"class Camera2D", &getComponentPtr<Camera2D> },
  11. {"class CameraController", &getComponentPtr<CameraController> },
  12. };
  13. const auto& type = j.at("type").get<std::string>(); // class name
  14. const auto& factfunc = functions.at(type); // get the function
  15. return factfunc(j); // and call it
  16. }
  17. } // namespace ns


要做到这一点,你还需要为你的类型添加nlohmann::adl_serializer专门化:

  1. namespace nlohmann {
  2. template <>
  3. struct adl_serializer<std::unique_ptr<ns::Camera2D>> {
  4. static std::unique_ptr<ns::Camera2D> from_json(const json& j) {
  5. const auto& data = j.at("data");
  6. return std::make_unique<ns::Camera2D>(
  7. data.at("graphicsContextIndex").get<std::size_t>(),
  8. data.at("viewSize").get<double>(),
  9. data.at("backgroundColor").get<std::array<double, 4>>()
  10. );
  11. }
  12. };
  13. template <>
  14. struct adl_serializer<std::unique_ptr<ns::CameraController>> {
  15. static std::unique_ptr<ns::CameraController> from_json(const json& j) {
  16. const auto& data = j.at("data");
  17. return std::make_unique<ns::CameraController>(
  18. data.at("strength").get<double>()
  19. );
  20. }
  21. };
  22. } // namespace nlohmann


Demo

展开查看全部

相关问题