项目中智能指针多态性丢失的问题
-
项目地址:https://github.com/FrozenLemonTee/original
是一个仿STL的工具库项目。问题源自于
transform
和transformStream
两个类的设计上。transform
是一个接口,通过继承这个类并且实现apply
方法,可以直接以仿函数的方式调用这个类,将定义好的变换施加给项目中继承了iterable
接口的可迭代对象中存放的所有元素。transformStream
是一个中间的临时类,同时和transform
一样也是可调用类,用于对若干个传入函数的transform
所构成的复合调用链进行管理,在自己被调用时按照调用链顺序依次调用相关的transform
以达到复合调用的目的。复合调用链用+
操作符进行连接,通过重载+
操作符自动生成transformStream
,并将调用链中的transform
加入生成的transformStream
的管理。在测试中发现,传入函数的复合调用链的每个
transform
派生类对象在被调用时,调用的是基类的apply
方法,而基类定义的是空操作,也就导致整个调用链被调用时不施加任何变换。经过检查是transformStream
的pushEnd
方法存在问题:template<typename TYPE> void original::transformStream<TYPE>::pushEnd(const transform<TYPE>& t) { this->stream.pushEnd(std::make_shared<std::decay_t<decltype(t)>>(t)); }
当以智能指针将传入的
transform
包装时,智能指针的参数无法获得传入的对象t
正确的派生类型,导致对象t
以基类的形式被存储。我尝试了很多方案想要解决这个问题,一开始怀疑是自定义的容器
chain
的问题,于是换成std::vector
,或者考虑以std::function
的方式存储变换,但是都无效,想请教一下如何设计可以避免这个问题? -
相关测试的例子在项目的test/test2.cpp中,最后几行就是针对该问题的测试
-
@FrozenLemonTee 在 项目中智能指针多态性丢失的问题 中说:
make_shared
如果传近来的是个const, 用make_shared创建对象的时候使用decay_t导致创建的就是基类对象了, 应该直接创建t的原类型, 向上转型自动会做
-
可以具体说一下怎么做吗
-
@FrozenLemonTee 在 项目中智能指针多态性丢失的问题 中说:
智能指针的参数无法获得传入的对象t正确的派生类型,导致对象t以基类的形式被存储。
发现你已经清楚是这个问题了, 对于涉及避免就是可能有两个简单的解决方法
- 1 想办法拿到真实类型, 如果过程中要重新创建对象
- 2 通过外部创建准确对象 然后 传递过程move指针
-
@FrozenLemonTee 避免创建对象, 如果必须创建 可以在最容易获取原对象的地方创建对象然后move
-
已完成。
最终解决方案是,通过cloneable接口的clone方法,实现具体类对象的动态创建:
https://github.com/FrozenLemonTee/original/commit/fe14776ccc411790084dcd4ea1a002d3ee22eaa7
https://github.com/FrozenLemonTee/original/commit/cdd94d92c29c09bb58ca4d6f4b9eadb8272e7e27