问题描述
我无法理解 shared_ptr
的转换。
This thread 很好地解释了普通指针的行为,结果非常直观 - 正是我所期望的。但是,shared_ptr
显示了不同的结果 - 我创建了 3 个类,一个 Base 和两个 Derived 并使用 ***_ptr_cast
进行了一些尝试:
#include <iostream>
#include <memory>
using namespace std;
struct Base
{
virtual void f() { cout << "Base" << endl; }
string name = "Base";
};
struct FirstDerived : public Base
{
void f() override { cout << "FirstDerived" << endl; }
void firstDerived() { cout << "FirstDerived only method" << endl; }
string name = "FirstDerived";
};
struct SecondDerived : public Base
{
void f() override { cout << "SecondDerived" << endl; }
void secondDerived() { cout << "SecondDerived only method" << endl; }
string name = "SecondDerived";
};
int main()
{
FirstDerived fd;
std::shared_ptr<Base> bf = make_shared<Base>(fd);
std::shared_ptr<FirstDerived> fdp = std::static_pointer_cast<FirstDerived>(bf);
if (fdp)
{
fdp.get()->f();
fdp.get()->firstDerived();
//cout << fdp.get()->name;
}
FirstDerived sd;
std::shared_ptr<Base> bs = make_shared<Base>(sd);
std::shared_ptr<SecondDerived> sdp = std::static_pointer_cast<SecondDerived>(bs);
if (sdp)
{
sdp.get()->f();
sdp.get()->secondDerived();
//cout << sdp.get()->name;
}
return 0;
}
这个程序的输出显示(有趣的是 cout << fdp.get()->name;
是不可能的,因为它会出现段错误):
Base
FirstDerived only method
Base
SecondDerived only method
进一步研究后我得出结论,static_cast
可能是错误的演员表,所以我将它们与 dynamic_cast
交换。然而,动态版本永远不会返回有效值,即使我正在转换为正确的派生版本。
希望的结果是,只有当初始对象的类型与下一步中要转换的对象的类型相同时,才会有结果。否则它应该为空。
我应该如何正确地执行此操作,是否有我正在搜索的内容的强制转换版本?
解决方法
您需要将 std::make_shared
中的类型分别更改为 FirstDerived
和 SecondDerived
。
此外,sd
的类型应为 SecondDerived
。
int main()
{
FirstDerived fd;
std::shared_ptr<Base> bf = make_shared<FirstDerived>(fd);
std::shared_ptr<FirstDerived> fdp = std::static_pointer_cast<FirstDerived>(bf);
if (fdp)
{
fdp.get()->f();
fdp.get()->firstDerived();
cout << fdp.get()->name;
}
SecondDerived sd;
std::shared_ptr<Base> bs = make_shared<SecondDerived>(sd);
std::shared_ptr<SecondDerived> sdp = std::static_pointer_cast<SecondDerived>(bs);
if (sdp)
{
sdp.get()->f();
sdp.get()->secondDerived();
cout << sdp.get()->name;
}
return 0;
}
这是一个 live demo。
编辑
根据 OP 的要求(example application 没有智能指针),他想向向量添加智能指针并动态调度存储的类型。为此,可以简单地创建一个向量 std::vector<std::shared_ptr<Base>> vec
并通过 vec.push_back(std::make_shared<FirstDerived>(fd))
或 vec.push_back(std::make_shared<SecondDerived>(sd))
添加元素。这是一个 example:
int main()
{
FirstDerived fd;
SecondDerived sd;
vector<std::shared_ptr<Base>> vec;
vec.push_back(std::make_shared<FirstDerived>(fd));
vec.push_back(std::make_shared<SecondDerived>(sd));
auto fdp = std::dynamic_pointer_cast<FirstDerived>(vec[0]);
auto sdp = std::dynamic_pointer_cast<FirstDerived>(vec[1]);
// true
if (fdp)
{
fdp->f();
fdp->firstDerived();
cout << fdp->name;
}
// false
if (sdp)
{
sdp->f();
cout << sdp->name;
}
return 0;
}
这给出了所需的输出:
FirstDerived
FirstDerived only method
FirstDerived