请参考下面的代码以了解详情,但基本情况如下。我有一个容器(会话),可以将对象放入其中并从中取出。
类似于:
请注意,一个会话可以存储异构类型,但在存储和加载时,我静态地知道变量的类型。我的问题是,我遇到了这样一种情况:用户想把一个“Tiger”放入会话,但却检出了一个基本类型。例如:
如果你运行这段代码,你会发现它会运行,但是它会调用
我的问题是,有没有一种好的方式来处理 C++ 中的这种情况。我查找了一些资料,但没有看到任何与我需要的内容相匹配的东西。
我所找到的关于异构容器的所有内容都假定存在共享的基类,而我既没有也不想要这样的基类。这可能吗?
类似于:
std::shared_ptr<Tiger> t = ...;
session.store("tigers/1", t);
std::shared_ptr<Tiger> t2 = session.load<Tiger>("tigers/1");
两个函数定义如下:
class Session {
template<class T>
void store(std::string id, std::shared_ptr<T> instance);
template<class T>
std::shared_ptr<T> load(std::string id);
}
请注意,一个会话可以存储异构类型,但在存储和加载时,我静态地知道变量的类型。我的问题是,我遇到了这样一种情况:用户想把一个“Tiger”放入会话,但却检出了一个基本类型。例如:
session.load<Animal>("tigers/1");
目前,我在会话中有效地将数据存储为void*
并使用reinterpret_cast
将它们转换回用户提供的类型。这个...可以工作,只要一切都是简单的,但当我们遇到稍微复杂一些的情况时,就会遇到问题。
这里是完整的代码,演示了我的问题:
struct Animal
{
virtual void Pet() const = 0;
};
struct IJumpable
{
virtual void Jump() const = 0;
};
struct Tiger : Animal, IJumpable
{
void Pet() const override
{
std::cout << "Pet\n";
}
void Jump() const override
{
std::cout << "Jump\n";
}
};
int main()
{
auto cat = std::make_shared<Tiger>();
// how the data is stored inside the session
auto any_ptr = std::static_pointer_cast<void>(cat);
// how we get the data out of the session
auto namable = std::static_pointer_cast<IJumpable>(any_ptr);
namable->Jump();
std::cout << std::endl;
}
如果你运行这段代码,你会发现它会运行,但是它会调用
Pet
而不是调用 Jump
。我明白这是因为使用了错误的虚函数表,因为实际上我在对 `void*` 进行了 reinterpret_cast
。我的问题是,有没有一种好的方式来处理 C++ 中的这种情况。我查找了一些资料,但没有看到任何与我需要的内容相匹配的东西。
我所找到的关于异构容器的所有内容都假定存在共享的基类,而我既没有也不想要这样的基类。这可能吗?
Session
类中,您保证只存储Animal
的基本类型吗? - Kunal Puristd::variant
吗?如果不是,您可以使用std::any
吗? - Krzysiek Karbowiakstd::any
,因为类型不匹配。`auto cat = new Tiger();auto any_ptr = std::any(cat);auto namable = std::any_cast<IJumpable*>(any_ptr); `这将导致错误的转换。 - Ayende Rahien