如何确保C ++中的运行时类型协方差?

时间:2018-12-06 00:21:57

标签: c++ covariance

说我有一个接口类和模板子类

struct IPort {
    virtual bool can_connect_to(std::shared_ptr<IPort> p) = 0;
    std::shared_ptr<IPort> receiver;
};

template <class T>
struct Port : IPort {
    bool can_connect_to(std::shared_ptr<IPort> p) override {
        // what goes here?
    }

    void send(T* t) {
        auto p = std::static_pointer_cast<Port>(receiver);
        p->on_recv(t);
    }

    std::function<void(T*)> on_recv;
};

template参数可以是任何类型。我有一些基本类型(下面的BaseOther)以及派生类型(Derived)。

struct Base {
    virtual const char* get_data() = 0;
    virtual size_t get_size() = 0;
};

struct Derived : public Base {
    std::string str;
    const char* get_data() override { return str.c_str(); }
    size_t get_size() override { return str.size(); }
};

struct Other {
    double x, y, z;
};

理想情况下,我应该能够将一个派生类型从一个端口发送到另一个接受基本类型的端口(例如Port<Derived>应该能够连接到Port<Base>)。另一方面,我应该不能发送不兼容的类型(Port<Other>应该不能连接到Port<Base>)。

auto sender1 = std::make_shared<Port<Derived>>();
auto sender2 = std::make_shared<Port<Other>>();
auto receiver = std::make_shared<Port<Base>>([](Base* t) {
    // do something with t
});

sender1->can_connect_to(receiver); // should return true
sender2->can_connect_to(receiver); // should return false

我可以在can_connect_to中输入什么内容来验证传入的端口是否具有模板类型,该类型是发送端口模板的超类?

此外,static_pointer_cast中的send为什么起作用?它似乎做对了,但是我不明白它甚至是有效的c ++,因为Port没有模板参数。

1 个答案:

答案 0 :(得分:1)

在运行时测试对象是否为某个类的“基本”的基本方法是dynamic_cast。所以我认为您需要:

template <class T>
bool Port<T>::can_connect_to(std::shared_ptr<IPort> p) {
    return dynamic_cast<T*>(p.get());
}

如果p是一个空指针,这也将返回false。

  

此外,static_pointer_cast中的send为什么起作用?它似乎做对了,但是我不明白它甚至是有效的c ++,因为Port没有模板参数。

在类模板的定义或其任何成员(或其嵌套类成员的成员等)的定义中,模板的名称可用作使用该模板的类类型的别名。定义的模板参数。也就是说,由于Port的使用出现在定义template <class T> struct Port { ... };内,因此没有模板参数列表的名称Port与{{1}相同}。这称为“注入的类名称”。