C++中如何通过字符串自动实例化第三方库的不同子类?
Solution 1: Registry-Based Factory (Template Metaprogramming)
This approach uses a singleton registry to map type strings to factory functions, with template helpers to automate registration of each derived class—no need to hardcode if-else chains.
#include <memory> #include <unordered_map> #include <functional> #include <string> // Third-party classes (unchanged) class obj { public: virtual std::string type() = 0; }; class subobj01 : public obj { public: std::string type() override { return "subobj01"; } }; class subobj02 : public obj { public: std::string type() override { return "subobj02"; } }; class subobj03 : public obj { public: std::string type() override { return "subobj03"; } }; // Registry to map type names to factory functions class ObjectFactoryRegistry { public: using FactoryFunc = std::function<std::shared_ptr<obj>()>; // Singleton instance static ObjectFactoryRegistry& instance() { static ObjectFactoryRegistry registry; return registry; } // Register a factory for a specific type void register_factory(const std::string& type_name, FactoryFunc func) { factories_[type_name] = std::move(func); } // Create an instance from a type string std::shared_ptr<obj> create(const std::string& type_name) const { auto it = factories_.find(type_name); if (it != factories_.end()) { return it->second(); } return nullptr; // Or throw std::invalid_argument for unknown types } private: ObjectFactoryRegistry() = default; std::unordered_map<std::string, FactoryFunc> factories_; }; // Template helper to auto-register derived classes template <typename Derived> class FactoryRegistrar { public: explicit FactoryRegistrar(const std::string& type_name) { ObjectFactoryRegistry::instance().register_factory( type_name, []() { return std::make_shared<Derived>(); } ); } }; // Register each third-party subclass (run once at program startup) static FactoryRegistrar<subobj01> registrar_subobj01("subobj01"); static FactoryRegistrar<subobj02> registrar_subobj02("subobj02"); static FactoryRegistrar<subobj03> registrar_subobj03("subobj03"); // Your desired create_instance function std::shared_ptr<obj> create_instance(std::shared_ptr<obj> o) { if (!o) return nullptr; return ObjectFactoryRegistry::instance().create(o->type()); }
Key Details:
- The
ObjectFactoryRegistrysingleton stores factory functions for each derived class. - The
FactoryRegistrartemplate automates registering each class's factory (std::make_shared<Derived>) when the program starts. - Adding new derived classes only requires a new
FactoryRegistrarinstance—no changes to the core factory logic.
Solution 2: Variant-Based Return (Strongly Typed Derived Instances)
If you need to work with specific derived types without manual casting, return a std::variant containing the derived shared pointers. Use std::visit to handle each type explicitly.
#include <variant> #include <stdexcept> #include <iostream> // Define a variant type covering all derived classes using ObjVariant = std::variant< std::shared_ptr<subobj01>, std::shared_ptr<subobj02>, std::shared_ptr<subobj03> >; ObjVariant create_instance_variant(std::shared_ptr<obj> o) { if (!o) throw std::invalid_argument("Null input object"); const std::string& type = o->type(); if (type == "subobj01") { return std::make_shared<subobj01>(); } else if (type == "subobj02") { return std::make_shared<subobj02>(); } else if (type == "subobj03") { return std::make_shared<subobj03>(); } throw std::invalid_argument("Unknown object type: " + type); } // Example usage with std::visit void process_new_instance(ObjVariant variant) { std::visit([](auto ptr) { std::cout << "Created instance of type: " << ptr->type() << "\n"; // Add type-specific logic here (ptr is strongly typed to the derived class) }, variant); }
Key Details:
ObjVariantacts as a type-safe container for any of the derived shared pointers.std::visiteliminates the need for manualdynamic_castby dispatching to a handler that works with each derived type directly.
内容的提问来源于stack exchange,提问作者J.W Kang
相关产品推荐
相关产品推荐

