簡體   English   中英

令人難忘的工廠和inheritance和層次結構的多個層次

[英]Unforgettable Factory and multiple levels of inheritance and hierachy

我一直在試驗這里描述的工廠實現:

http://www.nirfriedman.com/2018/04/29/unforgettable-factory/

該示例使用“Animal”作為基礎,使用“Dog”和“Cat”作為在工廠注冊的派生類。 但是現在假設我想添加一個派生自 Cat 的“Lion” class ......我如何在仍然向 Animal factory 注冊的同時從 Cat 派生? 此外,我還希望能夠創建一個“Cat”工廠,它可以讓我創建類型為“Cat”而不是“Animal”的 object。 這個例子可以適應這樣做嗎?

這是一些基於原始帖子的代碼,顯示了我正在嘗試做的事情。

#include <functional>
#include <memory>
#include <exception>
#include <iostream>
#include <string>
#include <map>
#include <unordered_map>
#include <cstdlib>
#include <cxxabi.h>

template<typename BaseT, typename ...Args>
class Factory
{
    public:

        friend BaseT;

        template<class ...T>
        static std::shared_ptr<BaseT> create(const std::string& name, T&&... args)
        {
            try
            {
                return types().at(name)(std::forward<T>(args)...);
            }
            catch(std::out_of_range e)
            {
                throw std::runtime_error("type \"" + name + "\" is not registered with the factory");
            };
        };


        template<typename T>
        struct Registrar : BaseT
        {

            public:

                friend T;

                static bool register_type()
                {
                    auto demangle = [](const char* name) -> std::string
                        {
                            int status = -4;
                            std::unique_ptr<char, void (*)(void *)> res{abi::__cxa_demangle(name, NULL, NULL, &status), free};
                            return (status == 0) ? res.get() : name;
                        };
                    const auto name = demangle(typeid(T).name());
                    std::cout << "registering " << name << "\n";
                    Factory::types()[name] = [](Args... args) -> std::shared_ptr<BaseT>
                    {
                        return std::make_shared<T>(std::forward<Args>(args)...);
                    };
                    return true;
                };

                static inline bool registered = register_type();

            private:

                Registrar() : BaseT() { (void) registered; };
        };

    private:

        using FunctionT = std::function< std::shared_ptr<BaseT>(Args...)>;

        static auto& types()
        {
            static std::unordered_map<std::string, FunctionT>  m_types;
            return m_types;
        };
};


struct Animal : Factory<Animal>
{
    virtual void speak() = 0;
    virtual ~Animal() = default;
};



// How can I create a Cat factory at this level in the hierarchy?
class Cat : public Animal::Registrar<Cat>
{
    public:

        Cat() {};

        virtual ~Cat() = default;

        virtual void speak() { std::cout << "Meow!" << "\n"; };
};

// I would like to register Lion with the Animal factory.
class Lion : public Cat 
{
    public:

        Lion() {};

        void speak() { std::cout << "Roar!" << "\n"; };

};


int main(int argc, char** argv)
{
    auto a = Animal::create("Cat");
    a->speak();

    auto lion = Cat::create("Lion"); // this doesn't work
    lion->speak();
    return 0;
};

我最終通過從Registrar器 class 的Base中刪除 inheritance 來稍微調整工廠 class。 我改變了這個:

template <class T> struct Registrar : Base {

對此:

template <class T> struct Registrar

回到我上面的例子,我現在像這樣使用工廠:

struct Animal
{
    virtual void speak() = 0;
    virtual ~Animal() = default;
};

using AnimalFactory = Factory<Animal>;


struct Cat : public Animal, public AnimalFactory::Registrar<Cat>
{
    <snip>
};

struct Lion : public Cat, public AnimalFactory::Registrar<Lion>
{
    <snip>
};

主要區別在於現在每個 class 都必須派生自Animal class 或子類以及AnimalFactory::Registrar類型。 它有點冗長,但我現在可以使用具有多個級別的 inheritance 的工廠。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM