10

我开始在 C++0X/11 中使用智能指针,但遇到了一个特殊的情况。我想使用 shared_ptr 向上转换一个对象的实例。

类 Extend 继承自类 Base,其中 Base 类有一个虚拟析构函数以使其具有多态性(否则 dynamic_pointer_cast 抱怨非多态类转换)。

如果因此:

std::shared_ptr<Base> obj = std::make_shared<Base>();

然后我做:

obj = std::dynamic_pointer_cast<Extend>(obj);
  1. 安全吗?
  2. 指向该对象的其他指针会发生什么?只有obj把它当作Extend,而其他共享指针仍然把它当作Base?
  3. 向上转换同一个实例是否安全,还是我应该做其他事情?

编辑:谢谢你的回答。我问这个问题的真正原因是使用 SAX 解析器处理 XML 文档,但我被向上/向下转换迷惑了。我想要的是:

std::shared_ptr<Extend> ex = std::dynamic_pointer_cast<Extend>(obj);
obj = ex;

但这根本没有意义,我将只使用对象工厂。

4

2 回答 2

10

这不是向上转换,而是向下转换(您正在从更少派生类转换为更多派生类)。然而:

安全吗?

是的,它是安全的,但是由于您试图向下转换指向运行时类型不是的对象的指针Extend,因此您将得到一个空指针作为回报。

指向该对象的其他指针会发生什么?只有obj把它当作Extend,而其他共享指针仍然把它当作Base?

您在这里有一个误解:向下转换指向对象的指针不会转换对象。如果对象不是目标类型,您将不会得到指向它的向下转换的指针。指向对象(任何对象)的类型在编译时确定并且不会改变。

向上转换同一个实例是否安全,还是我应该做其他事情?

不确定你在这里的意思,这个问题的提法可能源于上述误解。但是,这个指令:

obj = std::dynamic_pointer_cast<Extend>(obj);

obj生成一个空指针。赋值本身是合法的,因为您可以将指向派生类的(智能)指针分配给指向基类的(智能)指针。但是,由于赋值右侧的计算结果为空指针(由于上面写的内容),您最终将得到一个分配给obj.

由于您基本上只是在重置obj,如果obj是最后一个指向通过创建的对象的共享指针,make_shared<>()则执行上述分配后,该对象将被销毁。

于 2013-02-14T15:05:33.557 回答
7

如果底层对象确实属于该类型,则只能向下转换为超类型。铸造不能突然给你的底层对象新的属性。

std::make_shared<Base>();

威尔,在幕后呼叫:new Base

这意味着您不能:

obj = std::dynamic_pointer_cast<Extend>(obj);

比你可以用dynamic_cast在 a 上的任何new Base东西都可以使它变成它不是的东西。您需要make_shared<Extend>然后使用shared_ptr<Base>.

于 2013-02-14T15:01:20.687 回答