从shared_ptr到weak_ptr的多态转换

5

我很难理解这个问题。假设我有以下向量:

std::vector<std::shared_ptr<Car>> cars; 

Car是一个抽象类。我想能够返回不同类型的弱指针,所以我按照以下方式操作。

template<typename T>
    std::weak_ptr<T> GetCar()
    {
        for (std::vector<std::shared_ptr<Car>>::iterator it = cars.begin(); it != cars.end(); ++it)
        {
            T* derived = dynamic_cast<T*>((*it).get());
            if (derived != nullptr)
            {
                std::weak_ptr<T> carPointer = *it;
                return carPointer;
            }
        }
        return std::weak_ptr<T>();
    }

当我尝试使用从Car继承的类来使用该函数时,会出现以下错误:

Error C2440 'initializing': cannot convert from 'std::shared_ptr<Car>' to 'std::weak_ptr<Saab>'

在请求车辆时可能没有有效的汽车。 我尝试使用boost :: optional,但它无法处理多态性。 如果我无法使其工作,我可能会使用裸指针。


1
shared_ptrweak_ptr所指向的类型必须相同。我会分三步完成:首先返回一个weak_ptr<Car>,然后将其转换为shared_ptr<Car>,最后再转换为T* - Mark Ransom
感谢@MarkRansom的快速回答。嗯,这是针对库的用户函数,所以我不想给可能会使用它的开发人员更多的工作。应该说得更清楚一些,我的错。你建议只使用裸指针,这样我就可以返回一个吗?或者甚至返回派生类? - miniconco
你可以确实有一个单一的函数来执行所有三个步骤,但将weak_ptr转换为shared_ptr的目的是在你使用它时保持对象的存活状态;将shared_ptr放入一个临时变量中会破坏这个目的。 - Mark Ransom
std::weak_ptr<T> carPointer = std::shared_ptr<T>(*it); 这段代码能够正常工作吗? - user253751
1个回答

5
您不能直接从 shared_ptr<Car> 构造出您的weak_ptr<Saab>,因为模板参数Car必须隐式地转换为Saab才能工作。
但是您可以先将shared_ptr<Car> 转换为shared_ptr<Saab>,然后再构造您的weak_ptr。在下面的示例中,我使用了std::dynamic_pointer_cast来完成这个过程。
以下是我的解决方案:
#include <iostream>
#include <vector>
#include <memory>

struct Car
{
    virtual void name() = 0;
};

struct Saab : Car
{
    virtual void name() { std::cout << "Saab" << std::endl; }   
};

struct Renault : Car
{
    virtual void name() { std::cout << "Renault" << std::endl; }   
};

template<typename T>
std::weak_ptr<T> GetCar(std::vector<std::shared_ptr<Car>> cars)
{
    for (std::vector<std::shared_ptr<Car>>::iterator it = cars.begin(); it != cars.end(); ++it)
    {
        auto derived = std::dynamic_pointer_cast<T>(*it);
        if (derived != nullptr)
        {
            std::weak_ptr<T> carPointer(derived);
            return carPointer;
        }
    }
    return std::weak_ptr<T>();
}

int main()
{
    std::vector<std::shared_ptr<Car>> cars;
    cars.push_back(std::make_shared<Saab>());
    cars.push_back(std::make_shared<Renault>());

    auto wp = GetCar<Saab>(cars);

    auto sp = wp.lock();
    if (sp)
    {
        sp->name();
    }

    auto wp2 = GetCar<Renault>(cars);

    auto sp2 = wp2.lock();
    if (sp2)
    {
        sp2->name();
    }

}

它会打印出:

Saab

Renault

Coliru链接:http://coliru.stacked-crooked.com/a/9dbb85b556b83597


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接