我在c ++ 11中试验多态和boost :: variant
这是代码
#include <iostream>
#include <boost/variant.hpp>
using namespace std;
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{
width=a;
height=b;
}
};
class Rectangle: public Polygon {
public:
Rectangle() {
std::cout << "ctor rectangle" << std::endl;
}
int area()
{
return width*height;
}
};
class Triangle: public Polygon {
public:
Triangle() {
std::cout << "ctor triangle" << std::endl;
}
int area()
{
return width*height/2;
}
};
int main () {
Triangle r;
boost::variant<Rectangle, Triangle> container = r;
int x = 4;
int y = 5;
if (container.type() == typeid(Rectangle)) {
r.set_values(x,y);
std::cout << r.area() << std::endl;
} else if ( container.type() == typeid(Triangle)){
r.set_values(x,y);
std::cout << r.area() << std::endl;
}
return 0;
}
我想知道这是否是最好的方法。代码中有一个重复(在main()函数中),对于每种类型(我们在运行时获取类型),我们执行相同的操作,即设置值并打印区域。
有没有更好的方法呢?
答案 0 :(得分:1)
当你想要基于值类型变体的多态时,这是一个帮助器类。
template<class Base>
struct poly_ptr_t:boost::static_visitor<Base*> {
template<class T>
Base* operator()(T& t)const { return std::addressof(t); }
template<class...Ts>
Base* operator[](boost::variant<Ts...>& v) const {
return boost::apply_visitor( *this, v );
}
template<class...Ts>
Base const* operator[](boost::variant<Ts...> const& v) const {
return boost::apply_visitor( *this, v );
}
};
使用:
poly_ptr_t<Polygon> as_polygon;
int main() {
boost::variant<Triangle, Rectangle> u(Triangle{});
as_polygon[u]->set_values(x,y);
}
现在,area
有点痛苦。获取父级Polygon
无济于事,因为它没有区域。
如果我们添加了
virtual int area() = 0;
到Polygon
然后
std::cout << as_polygon[v]->area();
突然有效。
替代方案在C ++ 11中有点混乱。在具有适当boost
支持的C ++ 14中,我们得到:
std::cout << boost::apply_visitor( [](auto& e){return e.area();}, v );
或
boost::apply_visitor( [](auto& e){std::cout << e.area();}, v );
我们使用通用lambda来调用area
。
或者我们可以写一个区域访问者:
struct get_area:boost::static_visitor<int> {
template<class T>
int operator()(T& t)const{ return t.area(); }
};
现在我们可以这样做:
std::cout << boost::apply_visitor( get_area, v );
在这些情况中,我们都没有在main中重复代码。
答案 1 :(得分:0)
不要使用if-else结构。
看看boost。我在下面输入了一个小的未经测试的例子。
#include "boost/variant.hpp"
#include <iostream>
class my_visitor : public boost::static_visitor<void>
{
public:
void operator()(Rectangle const & i) const
{
// do something here
}
void operator()(Triangle const & i) const
{
// do something here
}
};
int main()
{
boost::variant< Triangle, Rectangle > u(Triangle());
boost::apply_visitor( my_visitor(), u );
}