c++ - 来自 void 的多态类型转换*

标签 c++

详情见下方代码,底层场景如下。我有一个容器(一个 session ),我可以将对象放入其中并从中取出。

类似于:

 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);
 }

请注意, session 可以存储异构类型,但在storeload 时我静态地知道变量的类型是什么。

我的问题是,我遇到了这样一种情况:用户想要将一个 Tiger 放入 session 中,但却 checkout 了一个基本类型。例如:

  session.load<Animal>("tigers/1");

现在,我有效地将数据存储为 session 中的 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;
}

如果您运行这段代码,您会看到它运行了,但它没有调用 Jump,而是调用了 Pet。我知道这是因为使用了错误的虚拟方法表,因为我实际上是在 `void* 上调用 reinterpret_cast

我的问题是在 C++ 中是否有处理这种情况的好方法。我环顾四周,没有看到任何符合我需要的东西。

我发现的关于异构容器的所有内容都假定有一个共享的基类,而我既没有也不需要。这可能吗?

最佳答案

您可以让用户为您提供正确的施法步骤:

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);

      template<class Stored, class Retrieved>
      std::shared_ptr<Retrieved> load_as(std::string id) {
          auto stored = load<Stored>(id);
          return std::static_pointer_cast<Retrieved>(stored);
      }
 }

这会在调用方站点造成困惑,但信息必须来自某个地方:

auto shere_khan = make_shared<Tiger>();
session.store("tigers/1", shere_khan);
auto bagheera = session.load_as<Tiger, IJumpable>("tigers/1");

关于c++ - 来自 void 的多态类型转换*,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54024018/

相关文章:

c++ - 拥有多态对象集合的首选 C++ 习惯用法是什么?

c++ - 使用伪代码协助 C++(溢出/下溢)

c++ - 如何修复循环依赖?

c++ - 确保在编译时调用方法

c++ - 为什么 {} 用于访问 std::hash 中的 operator()?

c++ - 无需创建 T 元素的 lower_bound 功能

java - JNI 从 DWord 返回值

c++ - 如何从提供的日志中收集相关信息?

C++ 手工制作的互斥体

c++ - 如何捕获 substr 异常?