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 中有代码重复。
我正在试验 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 中有代码重复。