继承类型的指针之间的静态转换

时间:2016-05-05 14:56:13

标签: c++ inheritance casting static-cast

我正在尝试这样做

{
    "_id" : 12345,
    "value" : {
        "cars" : true,
        "boats" : false
    }
}

其中B公开来自A.然而,这给出了错误

static_cast<IntrusivePtr<B>>(IntrusivePtr<A>)

有谁可以向我解释这里的问题?我可以通过做

来解决它
invalid conversion from A* to B*

理论上究竟是上述错误消息所说的内容是不允许的。这是GCC 4.4.7

3 个答案:

答案 0 :(得分:6)

您正在寻找的概念称为类型协方差 - 您希望IntrusivePtr<T>T上具有协变性,这意味着IntrusivePtr<D>是一个子类型如果IntrusivePtr<B>D的子类型,则为B。有类型系统支持的语言,C ++不是其中之一。

在C ++中,IntrusivePtr<A>IntrusivePtr<B>是完全不相关的类型,无论AB是什么(除非它们是相同的类型)。如果您想支持该转换,则必须明确支持:

template <class T>
struct IntrusivePtr {
    template <class U, class = std::enable_if_t<std::is_convertible<U*, T*>::value>>
    IntrusivePtr(IntrusivePtr<U> const& rhs) { ... }
};

或执行您正在执行的操作并侧重IntrusivePtr类模板。

回想起重新阅读问题时,IntrusivePtr似乎更有可能支持上述转换,但是在两种类型之间进行隐式转换 - 这对于派生到基础有效但对基础有效无效衍生。但是你总是可以从base-to-derived明确地转换。那就是:

struct B { };
struct D : B { };

B b;
D* d1 = &b;                  // error
D* d2 = static_cast<D*>(&b); // ok

答案 1 :(得分:1)

IntrusivePtr<A>IntrusivePtr<B>是完全不相关的类型。因此,您无法静态转换它们(除非IntrusivePtr包含显式转换代码或AB相同)。

请注意,您无法从基础静态转换为派生类。

答案 2 :(得分:1)

这是IntrusivePtr可以改变的一种方式。

rowRenderer

检查:

template <typename T>
struct IntrusivePtr {

    IntrusivePtr(const IntrusivePtr& other) {
         ... // do the refcounting
         ptr = other.ptr; // straight assignment, pointers are of the same type
    }

    template <typename Q,
       typename = std::enable_if_t<std::is_convertible<Q*, T*>::value>>
    IntrusivePtr(const IntrusivePtr<Q>& other) {
        ... // do the refcounting
        ptr = other.ptr; // straight assignment, pointers are compatible
    }

    // this can only be used in explicit conversions
    template <typename Q,
       typename = std::enable_if_t<std::is_convertible<T*, Q*>::value>>
    // must add bogus default parameter, or the compiler will complain
    explicit IntrusivePtr(const IntrusivePtr<Q>& other, int=0) {
        ... // do the refcounting
        ptr = static_cast<T*>(other.ptr); // explicit downcast, trust the programmer
    }
 ... // other methods

 T* ptr;

};

然而,如果IntrusivePtr离boost :: intrusive_ptr不太远,它应该有一个类似于struct A {}; struct B : A {}; IntrusivePtr<A> a; IntrusivePtr<B> b; a = a; // ok, straight copy a = b; // ok, implicit upcast b = static_cast<IntrusivePtr<B>>(a); // ok, explicit downcast b = a; // error, implicit conversion is not allowed 的函数。可能应该使用它,尤其是对于不支持C ++ 11的编译器。