假设我有一个Shape
基类和Circle
,Line
和Point
派生类。我有两个功能。
std::variant<Circle, Line, Point> process(const Shape &s);
Shape process(const Shape& s);
我可以传入我的任何派生类并在第二个函数中返回Shape对象,而变量只是一个联合,可以在任何给定时间保存我的任何派生类变量。
现在使用std::variant
,我也可以使用visitor
,在这里我可以根据变量当前所持的类型来处理某些函数(我可以创建一个函数对象并将其传递给{{1} }并将其应用于我的每个对象)。但是,我只可以在基类中创建该函数std::transform
并让每个派生类实现它。
那么virtual
只是一个方便吗?
答案 0 :(得分:4)
那么,变体只是一种方便吗?
不,它们是不同的概念。一方面std::variant
可以与不相关的类型(包括像int
这样的内建函数一起使用)的主要区别在于,直接使用虚函数是不可能的。另一方面,std::variant
必须在编译时知道它正在使用的类型。例如,可以通过以下方式添加带有虚函数的类型:仅链接其他对象模块,而无需重新编译其余代码或将共享库动态加载到现有应用程序(甚至不必重新启动应用程序),而使用{ {1}},您必须重新编译处理类型为std::variant
的代码。
答案 1 :(得分:2)
但是,我只能在基类中将该函数虚拟化,并让每个派生类实现它。
是的...。如果variant
中的所有元素都共享一个公共基数(Slava already mentioned)。
另一个巨大的区别是,使用variant
,在访问过程中根本没有任何动态多态发生(不需要RTTI)。
结合std::visit
,有很多技巧可以确保在为给定的std::variant
调用适当的函数时,(基本上)运行时开销为零。尽管可能会产生大量琐碎的编译时间和内存使用量,因为它通过创建大型函数指针矩阵(See this excellent blog post from Michael Park来实现)