C++ - unique_ptr 的 Cast/Change-type

C++ - Cast/Change-type of an unique_ptr

编辑:谢谢,一如既往的帮助:)

我找不到这个问题的解决方案,我有一个 unique_ptr 到一个基 class,它有一个派生 class 的数据,我想设置它是派生 class 的类型,因此我可以访问派生成员。请参阅此代码:

#include <memory>
#include <iostream>

class Base
{
public:
    int v1 = 0xAAAAAAAA;
};

class Derived : public Base
{
public:
    int v2 = 0xBBBBBBBB;
};

int main()
{

    std::unique_ptr<Base> b1(new Derived); //How to access b1->v2 ?
    std::unique_ptr<Base> b2(new Base);


    std::getchar(); 
    return 0;
}

b1的类型是Base,但是它的数据包含了Derived的数据。 参见:

很难得到吗?我考虑过操纵内存字节,比如说 [b1+4](伪想法)并访问它,但我考虑复杂的对象,因为我正在为游戏做一个实体系统,我不能这样做:(

谢谢!

正如 Sneftel 所建议的,您可以简单地转换包含在 unique_ptr 中的指针以访问其他方法。

static_cast<Derived*>(b1.get())->v2

请记住,这看起来很奇怪。通常,如果您可以访问给定类型的指针,则不应强制转换它以希望它具有您想要的类型。相反,如果您需要访问给定 subclass 的方法,您应该要求您的输入是该 subclass 的指针。在智能指针中存储基数 classes 通常是为了利用多态性,除此之外别无其他。

如果您不使用多态性,请考虑在模板中使用带有派生 class 的 unique_ptr,然后在只有基 class 接口时将其向下转换为基指针需要。

另一种选择是将同一个指针存储在两个位置:一个作为 Base,一个作为 Derived - 请记住,您只能使用一个智能指针其中之一!

您的选择是:

1) Cast C-like 指针(推荐)

std::unique_ptr<Base> b2(new Base);
Derived * p = static_cast<Derived *>(b2.get());

2) 实施您自己的 static_unique_ptr_cast,其中删除 b1 并创建新的 std::unique_ptr:

template<typename Derived, typename Base, typename Del>
std::unique_ptr<Derived, Del> 
static_unique_ptr_cast(std::unique_ptr<Base, Del> && p)
{
    auto d = static_cast<Derived *>(p.release());
    return std::unique_ptr<Derived, Del>(d, std::move(p.get_deleter()));
}

该函数采用右值引用以确保您不会从左值窃取资源。用法:

std::unique_ptr<Base> b1(new Derived);
std::unique_ptr<Derived> p = static_unique_ptr_cast<Derived>(std::move(b1));

注意:如果您认为需要使用 2),我会认为您的设计存在缺陷。由于某种原因演员表不在 STL 中。

编辑: static_unique_ptr_cast 现在保留删除器。

如果使用 shared_ptr

,则可以使用共享指针转换
std::static_pointer_cast<Derived>(b1)->v2;

您的整个问题在 cppreference 网站上都有解释:http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast

我会注意其他建议,标准确实考虑到了这个问题并实施了一个干净的解决方案。

我不确定我是否理解您正在尝试做的事情,但它看起来更像是一个设计问题。

如果您有指向 Base 的指针,则实际对象可能是 Base 或派生对象 class(不一定是派生对象)。也就是说,如果不做一些危险的假设,就不能将其转换为 Derived。

class B{public:virtual ~B(){}};
class D : public B{};
class DD : public B{};

int main()
{
  std::unique_ptr< B > pb( new D );
  D* pd = dynamic_cast< D* >( pb.get() );
  DD* pdd = dynamic_cast< DD* >( pb.get() ); // null
  return 0;
}