【发布时间】:2019-11-10 12:52:13
【问题描述】:
目前,我将不同类型的指针存储在向量中。为了归档这个,我实现了一个类模板“Store”,它派生自一个非类模板“IStore”。我的向量最终存储了指向“IStore”的指针。 在代码中:
class IStore
{
public:
IStore() = default;
virtual ~IStore() = default;
virtual void call() = 0;
// ... other virtual methods
};
template<typename T>
class Store : public IStore
{
public:
Store() = default;
virtual ~Store() = default;
virtual void call() override;
// ... other virtual methods
private:
T* m_object = nullptr;
}
在我持有向量的主类中:
class Main
{
public:
template<typename T>
void registerObject(T* ptr);
template<typename T>
void callObjects();
// ... other methods
private:
std::vector<IStore*> m_storedObjects;
};
目前为止的类结构。为了描述这个问题,我需要介绍以下三个示例结构:
struct A {}
struct B : public A {}
struct C : {}
其他类应该使用指向 A、B 或 C 类型对象的指针调用 Main::registerObject 方法。然后,此方法将分别创建一个新的 Store、Store。存储
现在开始棘手的部分:方法 Main::callObjects 应该由其他类使用模板参数调用,例如 Main::callObjects()。这应该遍历 m_storedObjects 并为每个对象调用 IStore::call 方法,该对象属于 B 类型或 B 派生自哪个类型。
例如:
Main::registerObject<A>(obj1);
Main::registerObject<B>(obj2);
Main::registerObject<C>(obj3);
Main::callObjects<B>();
应该调用 obj1 和 obj2 而不是 obj3,因为 C 不是 B 并且 B 不是从 C 派生的。
我在 Main::callObjects 中的方法是: 1. 执行 dynamic_cast 并检查 nullptr 如:
for(auto store : m_storedObjects)
{
Store<T>* base = dynamic_cast<Store<T>*>(store);
if(base)
{
// ...
}
}
这将只适用于相同的类,而不是派生类,因为 Store 不是从 Store 派生的。 2.覆盖IStore和Store中的cast操作符,这样当模板参数是可转换的时,我可以指定Store应该是可转换的。例如在商店中:
template<typename C>
operator Store<C>*()
{
if(std::is_convertible<T, C>::value)
{
return this;
}
else
{
return nullptr;
}
}
但是这个方法永远不会被调用。
有没有人能解决这个问题? 很抱歉,这篇文章很长,但我认为更多的代码会更好地理解这个问题。 无论如何感谢您的帮助:)
【问题讨论】:
-
在调用
Main::callObjects<B>()时,您想调用B 或B 的祖先 上的方法吗?这很有趣,因为您可以安全地将B转换为A,但一般情况下,不能反过来。 -
我遇到了一些困难,因为你不能有虚拟模板成员函数,这在这种情况下会很有帮助。
-
虚拟模板方法可以完全解决这个问题,但是模板是编译时,虚拟成员是运行时组件,所以很遗憾根本不可能。我还考虑了 Store 类中的静态成员,但我认为不可能从 IStore 中获得正确的 Store 模板类......我也不害怕改变存储机制,但我需要存储不同的数据类型在向量中,我找不到任何其他解决方案来存档这个......此外,我不限于 C++11,如果有人想出一个需要 C++14 或 C++17 的解决方案,没关系:)
-
添加了 C++17 解决方案。
标签: c++ c++11 templates casting