尽管这段代码可以工作,但我想知道是否有什么情况我没有预料到,和/或我试图做的是什么错误。
#include <iostream>
#include <string>
#include <map>
#include <typeinfo>
#include <functional>
class object
{
public:
virtual ~object(){}
virtual std::string to_string() = 0;
};
class SomeObject : public object
{
public:
SomeObject(){}
virtual ~SomeObject(){}
virtual std::string to_string()
{
return "I am a type of SomeObject";
}
};
class SomeOtherObject : public object
{
public:
SomeOtherObject(){}
virtual ~SomeOtherObject(){}
virtual std::string to_string()
{
return "I am a type of SomeOtherObject";
}
};
std::map<std::string, std::function<object*()> > types;
template<typename O>
inline
static void register_type(const std::string & name)
{
types[name] = [](){ return new O; };
}
static object * get_object(const std::string & object_name )
{
return types[object_name]();
}
int main()
{
register_type<SomeObject>("SomeObject");
register_type<SomeOtherObject>("SomeOtherObject");
object * some = get_object("SomeObject");
object * some_other = get_object("SomeOtherObject");
std::cout << "::" << some->to_string() << std::endl;
std::cout << "::" << some_other->to_string() << std::endl;
delete some;
delete some_other;
std::cout << "exit" << std::endl;
return 0;
}发布于 2015-12-20 22:39:25
一般来说,您的代码看起来很好,尽管有一些需要改进的地方:
与其使用原始指针和new delete,不如使用智能指针显式地表示所有权的传递:
template<typename O>
void register_type(const std::string & name) {
types[name] = [](){ return std::unique_ptr<O>(new O); };
}
std::unique_ptr<object> get_object(const std::string & object_name ) {
return types[object_name]();
}因此很明显,调用方将拥有object实例,并且在获得的实例超出作用域时不需要正确调用delete。
模板参数更常见的名称是T而不是O
。
将register_type()、get_object()函数和types映射变量的代码合并到一个class Registry中,并提供该实例的一个实例。
这将允许将types映射封装为私有类成员。
你可以考虑把那门课变成单身。
您应该检查传递给get_object()函数的字符串是否已经在映射中注册,而不是从映射中盲目地调用默认(NOP)函数。
全局函数
static的使用您应该知道,static实际上使register_type()函数只对翻译单元可见,它出现在。其实你不应该需要它。
顺便说一句,您使用的技术通常用于单元测试框架(例如google- test )作为测试用例工厂,也经常伴随着注册类的字符串化宏。
发布于 2015-12-20 22:24:08
>>不是shift操作符。register_type static和inline?我觉得这两个人都说不通。T作为模板参数类型是非常常见的,O不太常见,这使得代码很难阅读。std::unique_ptr,因为它将在默认情况下防止泄漏。如果人们不喜欢它,他们可以调用.release(),所以您不会失去灵活性。std::endl的风格很糟糕,因为它会冲淡输出,不必要地放慢程序的速度。register_type以接受非默认可构造的类型。发布于 2015-12-23 16:37:12
在您的SomeObject和SomeOtherObject类中,您是否期望它们也会被继承?如果没有,则删除virtual并从C++11中使用override上下文关键字。这将允许您将覆盖toString()函数的意图显式化,并提供编译时检查,以确定是否真正覆盖正确的函数。在这个特定的例子中,这可能有些过分(因为它的简单性),但这是一个很好的习惯。您还可以删除这些类的默认ctors和dtors的不必要定义(因为编译器会自动为您提供它们)。
class object
{
public:
virtual ~object(){}
virtual std::string to_string() = 0;
};
class SomeObject : public object
{
public:
std::string to_string() override
{
return "I am a type of SomeObject";
}
};
class SomeOtherObject : public object
{
public:
std::string to_string() override
{
return "I am a type of SomeOtherObject";
}
};正如其他人所提到的,将全局映射和注册表/取消注册函数转换为可以管理自己状态的类。此外,这里使用std::unique_ptr而不是运算符new。
替换std::map
看起来您不需要std::map给您的排序(以及相应的log(n)插入时间)。如果要查找哈希表(摊销的O(1)插入/检索),则使用std::unordered_map。
扩展register_type()
为此使用各种模板:
struct Registry
{
template <class T, class... Args>
static void register_type(const std::string &name, Args&&... args)
{
types[name] = [&args...]() { return std::make_unique<T>(std::forward<Args>(args)...); };
}
static std::unique_ptr<object> get_object(const std::string &name)
{
return types[name]();
}
private:
static std::unordered_map<std::string, std::function<std::unique_ptr<object>()>> types;
};https://codereview.stackexchange.com/questions/114578
复制相似问题