c ++ 11中的boost :: variant和polymorphism

时间:2017-06-01 15:42:55

标签: c++ c++11 boost boost-variant

我在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()函数中),对于每种类型(我们在运行时获取类型),我们执行相同的操作,即设置值并打印区域。

有没有更好的方法呢?

2 个答案:

答案 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 );
}