除了其他答案之外,您还可以这样做,假设每个 Text 键唯一地对应于具有已知不同 Type 的资源:
class BaseText
{
// constructors that take const char *, std::string, etc.
// .. whatever else you currently have in class Text
};
template<typename Type>
class Text : public BaseText
{
// constructors that take const char *, std::string, etc.
};
然后将ResourceManager改为:
class ResourceManager
{
template<typename Type>
Type RetrieveResource( Text<Type> name );
};
注意这仍然需要编译时多态性,但这意味着只要您的用户可以获得正确类型的Text<Type>,他们就可以使用它来获取正确类型的资源,而无需显式提供@987654327 @ 参数,所以它看起来像一个普通的函数调用。
如果可以使用正确的类型静态声明和初始化可能的 Text<Type> 对象集,这很容易实现,我不确定在您的情况下是否正确。相反,如果用户必须能够在运行时创建它们,那么他们将需要知道要创建的正确类型,所以它只是将问题推回了一点:但是,如果相同的话,它可能会很方便Text<Type> 对象会被反复使用。
请注意,如果您或客户需要将不同的 Text<Type> 对象存储在某种数据结构中,您也很不走运,因为这需要某种类型的擦除(即向上转换为 BaseText) .所以这在某种程度上是一种专门的解决方案,但它可能很有用,具体取决于事物的结构(如果没有看到更多代码,我真的无法知道)。
编辑:根据下面的评论,对象的类型似乎是由客户端在插入对象时确定的,因此您可以执行以下操作:
class ResourceManager
{
BaseText PutResource( const BaseText& name, BaseResource& resource );
template<typename Type>
Text<Type> PutResource( const BaseText& name, Type& resource );
BaseResource& RetrieveResource( const BaseText& name );
template<typename Type>
Type& RetrieveResource( const Text<Type>& name );
};
因此,客户端需要保留唯一的类型化密钥对象,以便稍后检索资源;如果他们选择通过向上转换回BaseText 来擦除类型信息,那么他们将负责正确恢复类型信息,方法是在检索之前向下转换密钥或在之后向下转换资源。
请注意,这只是您无论如何都必须做的事情之外的一个额外选项:如果您想使用非类型特定的键提供对资源的访问,唯一的方法是返回一个非- 特定的资源类型(即BaseResource、boost::any、boost::variant<...> 或它们的道德等价物之一。)但是,创建BaseText 的特定于类型的子类允许您获得正确类型的资源,使用确切的相同的语法(即不需要显式模板参数)。此外,这允许以下用法:
// tree is a resource of type `Tree`
auto key = manager.PutResource("Tree01", tree);
// ...
const BaseText& basekey = key; // lose type information
// ...
// these are all equivalent
Tree& tree = dynamic_cast<Tree&>(manager.RetrieveResource("Tree01"));
Tree& tree = dynamic_cast<Tree&>(manager.RetrieveResource(basekey));
Tree& tree = manager.RetrieveResource(key); // no casts required
Tree& tree = manager.RetrieveResource<Tree>("Tree01")
dynamic_cast 版本基本上是您在没有这些模板化重载的情况下需要执行的操作,但其他两个版本是除此之外的额外选项,您可以使用这种方法而无需任何运行时成本。