#include <iostream> #include <string> using namespace std; class Shape { public: virtual void calc_area() { cout << "call Shape::calc_area" << endl; } }; class Circle : public Shape { public: virtual void calc_area() { cout << "call Circle::calc_area" << endl; } }; class Square : public Shape { public: virtual void calc_area() { cout << "call Square::calc_area" << endl; } }; class Rectangle : public Shape { public: virtual void calc_area() { cout << "call Rectangle::calc_area" << endl; } }; int main() { Shape* pB = new Shape; pB->calc_area(); //call Shape::calc_area delete pB; Shape* pC = new Circle; pC->calc_area(); //call Circle::calc_area delete pC; Shape* pS = new Square; pS->calc_area(); //call Square::calc_area delete pS; Shape* pR = new Rectangle; pR->calc_area(); //call Rectangle::calc_area delete pR; system("pause"); }
#include <iostream> #include <string> using namespace std; class Shape { public: virtual void calc_area() { cout << "call Shape::calc_area" << endl; } }; class Circle : public Shape { public: virtual void calc_area() { cout << "call Circle::calc_area" << endl; } }; class Square : public Shape { public: virtual void calc_area() { cout << "call Square::calc_area" << endl; } }; class Rectangle : public Shape { public: virtual void calc_area() { cout << "call Rectangle::calc_area" << endl; } }; class ShapeFactory { public: static Shape* createShape(std::string type) { if ("circle" == type) { return new Circle; } if ("square" == type) { return new Square; } if ("rectangle" == type) { return new Rectangle; } return nullptr; } }; int main() { Shape* ptr = ShapeFactory::createShape("circle"); if (ptr != nullptr) { ptr->calc_area(); //call Circle::calc_area delete ptr; } system("pause"); }
#include <string> #include <iostream> #include <unordered_map> using namespace std; class Shape { public: virtual void calc_area() { cout << "call Shape::calc_area" << endl; } }; class Circle : public Shape { public: virtual void calc_area() { cout << "call Circle::calc_area" << endl; } }; class Square : public Shape { public: virtual void calc_area() { cout << "call Square::calc_area" << endl; } }; class Rectangle : public Shape { public: virtual void calc_area() { cout << "call Rectangle::calc_area" << endl; } }; typedef void* (*pCreateShape)(void); class CShapeFactory { public: ~CShapeFactory() = default; public: void* getShapeByName(const std::string& className) { auto iter = m_mapCShape.find(className); if (iter == m_mapCShape.end()) return nullptr; return iter->second(); } void registoryClass(const std::string& name, pCreateShape method) { m_mapCShape.insert(make_pair(name, method)); } static CShapeFactory& getInstance() { static CShapeFactory oFactory; return oFactory; } private: CShapeFactory() {}; std::unordered_map<std::string, pCreateShape> m_mapCShape; // 引入map }; // 注册动作类 class CRegisterAction { public: CRegisterAction(std::string className, pCreateShape pCreateFn) { CShapeFactory::getInstance().registoryClass(className, pCreateFn); } }; #define REGISTER_SERVICE(className) \ className* create##className() { \ return new className; \ } \ CRegisterAction createRegister##className( \ #className, (pCreateShape)create##className) REGISTER_SERVICE(Circle); REGISTER_SERVICE(Square); REGISTER_SERVICE(Rectangle); int main() { for (auto& item : { "Circle", "Square", "Rectangle" }) { auto pShape = (Shape*)CShapeFactory::getInstance().getShapeByName(item); if (pShape != nullptr) { pShape->calc_area(); delete pShape; } } system("pause"); } /* result: call Circle::calc_area call Square::calc_area call Rectangle::calc_area 请按任意键继续. . . */
factory.hpp
#pragma once #include <memory> #include <functional> #include <unordered_map> #include <utility> // ref: http://www.nirfriedman.com/2018/04/29/unforgettable-factory/ namespace prefab { namespace patterns { template<typename I, typename Identify, typename... Args> class factory { friend I; using K = decltype(Identify::key); //typename Identify::key_type; using V = decltype(Identify::value);// typename Identify::value_type; struct key { key() {}; template<typename T> friend struct registar; }; factory() = default; using builder = std::function<std::unique_ptr<I>(Args...)>; using reader = V(*)(); static auto& builders() { static std::unordered_map<K, builder> container; return container; } static auto& readers() { static std::unordered_map<K, reader> container; return container; } public: using self = factory<I, Identify, Args...>; template<typename... Ts> static std::unique_ptr<I> make(K const& k, Ts&&... args) { auto it = builders().find(k); if (it == builders().end()) return nullptr; return it->second(std::forward<Ts>(args)...); } static std::pair<bool, V> identify(K const& k) { std::pair<bool, V> result; result.first = false; auto it = readers().find(k); if (it == readers().end()) return result; result.first = true; result.second = it->second(); return result; } template<typename T> struct registar : I { friend T; static bool register_() { const auto r = T::identify().key; factory::builders()[r] = [](Args&&... args)->std::unique_ptr<I> { return std::make_unique<T>(std::forward<Args>(args)...); }; factory::readers()[r] = []()->V { return T::identify().value; }; return true; } static bool registered; private: registar() : I(key{}) { (void)registered; } }; }; template<typename I, typename Identify, typename... Args> template<typename T> bool factory<I, Identify, Args...>::registar<T>::registered = factory<I, Identify, Args...>::registar<T>::register_(); } } #if 0 #include <iostream> #include <string> namespace prefab_patterns_example { template<typename I, typename Identify, typename... Args> using Factory = prefab::patterns::factory<I, Identify, Args...>; struct task_identify { std::string key; std::string value; }; struct task :public Factory<task, task_identify, int> { task(self::key) {}; virtual void execute() = 0; }; struct print :task::registar<print> { print(int) {}; void execute()override { std::cout << "print\n"; }; static task_identify identify() noexcept { (void)registered; // MSVC has bug,use this force register return task_identify{ "print","task_print" }; } }; } #endif
CShapeFactory.hpp
#include <string> #include <iostream> #include "factory.hpp" template<typename I, typename Identify, typename... Args> using Factory = prefab::patterns::factory<I, Identify, Args...>; struct IShape_identify { std::string key; std::string value; }; struct IShape : public Factory<IShape, IShape_identify> { IShape(self::key) {}; virtual void calc_area() = 0; }; struct Circle : public IShape::registar<Circle> { public: Circle() {} virtual void calc_area() { std::cout << "call Circle::calc_area" << std::endl; } static IShape_identify identify() noexcept { (void)registered; //MSVC has bug,use this force register return IShape_identify{ "C", "Circle" }; } }; struct Square : public IShape::registar<Square> { public: Square() {} virtual void calc_area() { std::cout << "call Square::calc_area" << std::endl; } static IShape_identify identify() noexcept { (void)registered; //MSVC has bug,use this force register return IShape_identify{ "S", "Square" }; } }; struct Rectangle : public IShape::registar<Rectangle> { public: Rectangle() {} virtual void calc_area() { std::cout << "call Rectangle::calc_area" << std::endl; } static IShape_identify identify() noexcept { (void)registered; // MSVC has bug,use this force register return IShape_identify{ "R", "Rectangle" }; } };
main.cpp
#include "CShapeFactory.hpp" int main() { for (auto& item : { "C", "S", "R" }) { auto target = IShape::make(item); if (target != nullptr) { target->calc_area(); } } system("pause"); } /* result: call Circle::calc_area call Square::calc_area call Rectangle::calc_area 请按任意键继续. . . */
关于CRTP,详见随笔《C++ CRTP》
编译错误:C7510 “registar”: 模板从属名称的使用必须以“模板”为前缀
解决方案:本地VS2019,关闭工程的“符合模式”即可(默认开启),如下图: