boost::variant 和 c++11 中的多态性

boost::variant and polymorphism in c++11

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

有没有更好的方法来做到这一点?

不要使用 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 );
}

当您需要基于值类型变量的多态性时,这是一个帮助程序 class。

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 );

在 none 这些情况下,我们在 main 中有代码重复。