与传统的多态处理相比,使用 std::variant 有啥优势?
Posted
技术标签:
【中文标题】与传统的多态处理相比,使用 std::variant 有啥优势?【英文标题】:What are the advantages of using std::variant as opposed to traditional polymorphic processing?与传统的多态处理相比,使用 std::variant 有什么优势? 【发布时间】:2018-09-12 13:54:13 【问题描述】:假设我有一个Shape
基类和Circle
、Line
和Point
派生类。我有两个功能。
std::variant<Circle, Line, Point> process(const Shape &s);
Shape process(const Shape& s);
我可以传入我的任何派生类并在第二个函数中返回一个 Shape 对象,变体只是一个联合,可以在任何给定时间保存我的任何派生类变量。
现在有了std::variant
,我还可以使用visitor
,我可以根据我的变体当前持有的类型来处理一些函数(我可以创建一个函数对象并将其传递给std::transform
并将其应用于每个我的对象)。但是,我可以在我的基类中创建该函数 virtual
并让每个派生类实现它。
那么,variant
只是为了方便吗?
【问题讨论】:
您似乎认为std::variant
的模板参数必须共享一个共同的基础。您可以将不相关的类型存储在 std::variant
中。
恕我直言太宽泛了,虽然最明显的是你可以将任何类型放入一个变体中,而你不能多态地使用Circle
和Rectangle
,除非它们都继承Shape
,这是一个很小但很大的区别
例如std::variant<int,double,std::string>
,没有机会通过继承获得接近它的任何地方
FWIW:Shape process(const Shape& s)
与 std::variant<Circle, Line, Point> process(const Shape &s)
与前slices the object 不同。您需要通过引用/智能指针/指针返回。
不错的比较在这里:Inheritance vs std::variant
【参考方案1】:
那么,变体只是为了方便吗?
不,它们是不同的概念。主要区别在于,一方面std::variant
可以使用不相关的类型,包括像int
这样的内置函数,而直接使用虚函数是不可能的。另一方面,std::variant
必须知道它在编译时使用的类型。例如,可以通过仅链接附加对象模块而无需重新编译其余代码或将共享库动态加载到现有应用程序(您甚至不必重新启动应用程序)来添加具有虚函数的类型,而使用 @ 987654324@ 必须重新编译处理 std::variant
包含的类型的代码。
【讨论】:
【参考方案2】:但是,我可以在我的基类中将该函数设为虚拟,并让每个派生类实现它。
是的....如果variant
中的所有元素共享一个公共基础(Slava already mentioned)。
另一个很大的区别是,对于 variant
,在访问期间不一定任何动态多态性发生(不需要 RTTI)。
与std::visit
一起使用,有很多技巧可以确保在调用给定std::variant
的适当函数时(基本上)零运行时开销。虽然可能会有不小的额外编译时间和内存使用,因为它通过创建一个大的函数指针矩阵来做到这一点(See this excellent blog post from Michael Park 关于它)
【讨论】:
以上是关于与传统的多态处理相比,使用 std::variant 有啥优势?的主要内容,如果未能解决你的问题,请参考以下文章
[Golang]面向对象营养餐,一文管够(封装,继承,多态)
hadoop与传统的关系型数据库(如oracle)相比,有啥优势及劣势?