将共享指针的派生类切换到基类
Posted
技术标签:
【中文标题】将共享指针的派生类切换到基类【英文标题】:Switch Derived class of a shared pointer to base class 【发布时间】:2016-10-11 11:21:32 【问题描述】:我目前正在尝试将存储在共享指针中的派生类的类型切换到基类。 问题是 Derived 类继承自 Base 类,并且模板化如下:
基类:
#define PRINT(s) std::cout << s << std::endl
class Base
public:
Base() : m_a(1)
virtual ~Base() = default;
virtual void print() PRINT("BASE");
int m_a;
;
派生类依赖于枚举模板:
enum eType e0, e1 ;
template<eType et>
class Derived : public Base ;
template<>
class Derived<e0> : public Base
public:
Derived() this->m_a = e0;
void print() PRINT("Derived e0, m_a value: " << e0 );
;
template<>
class Derived<e1> : public Base
public:
Derived() this->m_a = e1;
void print() PRINT("Derived e1, m_a value: " << e1 );
;
我的目标是拥有一个指向基类的共享指针,这样就可以从 2 个派生类切换如下:
int main()
std::shared_ptr<Base> sp_00 = std::make_shared<Derived<e0>> ();
std::shared_ptr<Base> sp_01 = sp_00;
sp_01->print();
std::shared_ptr<Base> sp_10 = std::make_shared<Derived<e1>> ();
*sp_01 = *sp_10;
sp_01->print();
sp_10->print();
*sp_01 = *sp_10;
行上的唯一问题我希望指向基类的指针从派生类型 Derived<e0>
切换到派生类型 Derived<e1>
。但是在我的示例中,sp_01->print();
行和sp_10->print();
行得到了不同的结果,表明sp_01
保持为Derived<e0>
类型。
我想避免sp_01 = sp_10;
,因为它会改变指针。在上面的示例中,它将导致sp_00 != sp_01
,我希望sp_00
和sp_01
共享同一个对象。
我尝试用非模板派生类替换模板派生类,如下所示:
class Derived_e0 : public Base
public:
Derived() this->m_a = e0;
void print() PRINT("Derived e0, m_a value: " << e0 );
;
class Derived_e1 : public Base
public:
Derived() this->m_a = e1;
void print() PRINT("Derived e1, m_a value: " << e1 );
;
下面的代码给出的结果与带有模板的代码相同。
int main()
std::shared_ptr<Base> sp_00 = std::make_shared<Derived_e0> ();
std::shared_ptr<Base> sp_01 = sp_00;
sp_01->print();
std::shared_ptr<Base> sp_10 = std::make_shared<Derived_e1> ();
*sp_01 = *sp_10;
sp_01->print();
sp_10->print();
所以我的问题是,如何在不改变shared_ptr本身的情况下切换共享指针指向的派生对象(在程序的其他部分使用?)
谢谢,如果您需要更多信息,请告诉我
【问题讨论】:
如果不重新分配sp_01
,就无法更改sp_01
的“多态类型”。如果Derived<e0>
和Derived<e1>
的大小不同,你怎么能做到这一点?你的设计(或你试图做的)可能有缺陷。
【参考方案1】:
您无法更改 sp_01
的运行时类型而不重新分配它,因为您无法将 Derived<e1>
分配给 Derived<e0>
(想想如果它们的大小不同会发生什么 - 您已为Derived<e0>
,而不是Derived<e1>
!)。
在我看来,你的设计(或你试图用它做什么)在某个地方存在缺陷。但是,如果您真的想在sp_00
和sp_01
之间保持“链接”,您可能需要另一个“级别”的指针:
int main()
std::shared_ptr<Base> *psp_01;
std::shared_ptr<Base> sp_00 = std::make_shared<Derived<e0>> ();
psp_01 = &sp_00;
(*psp_01)->print();
std::shared_ptr<Base> sp_10 = std::make_shared<Derived<e1>> ();
psp_01 = &sp_10;
(*psp_01)->print();
sp_10->print();
但同样,我会在使用它之前对我的设计进行两次分析。
【讨论】:
感谢您的回复,它适用于预期的行为。我想你对设计是对的,我会尝试改变它。如果我有sp_00
、sp_01
和其他 shared_ptr 共享同一个派生类,是否可以有一个函数调用所有这些实例并将它们重新分配给同一个 shared_ptr ?使用全局向量是可能的,但我想这是一种不好的做法^^
@SchneiderLoïc 不,将*sp_00
分配给*sp_01
实际上会调用Base
的operator=(Base const&)
,这会将sp_01
的Base
部分重新分配给sp_00
(通常,在您的情况下,m_a
将被重新分配,但不是仅在 Derived<e0>
或 Derived<e1>
中的东西。
@SchneiderLoïc 参见rextester.com/TJEAV61599,重新分配*pxa = *pxb
时,仅重新分配X
的x_
,y_
属性保留为1
,即使Y<1>
和Y<2>
相似(但它们不是同一类!)。在这种情况下,尝试将 pxa
转换为 Y<2>*
甚至会失败 - 运行时类型不会随分配而改变。【参考方案2】:
您可以动态转换原始指针;像
Derived* t = dymanic_cast<Derived*>(sp_00.get())
如果不能强制转换,你会得到 NULL,如果可以,你会得到一个有效的指针。也就是说,这需要内置 RTTI,这会使您的二进制文件变大,而完全需要这样做表明您的设计不正确。
【讨论】:
以上是关于将共享指针的派生类切换到基类的主要内容,如果未能解决你的问题,请参考以下文章