boost 变体:获取提供变体的泛型 class 的指针
boost variant: Get pointer of generic class providing a variant
我有一个 boost::variant
定义如下:
typedef boost::variant<Rectangle, Circle> Shape;
现在我想从 Rectangle
得到一个 Shape
指针:
Rectangle *rectanglePointer = new Rectangle();
Shape *shapePointer = rectanglePointer;
但是没用。我在这里弄错了什么?
简单。变体不是那样工作的。
它们专门用于静态多态性。
您/可以/存储运行时多态引用(或指针),但您仍然需要使用 boost::get<>
或访问者来提取实际值。
在你的例子中,Shape
显然不是 Rectangle
的基础 class,这就是编译器将拒绝静态转换的原因(up-cast 不适用于不相关的类型 Rectangle
和 Shape
).
变体,简单
带有变体的简单示例:
#include <boost/variant.hpp>
#include <iostream>
struct Circle {
friend std::ostream& operator<<(std::ostream& os, Circle) {
return os << "Circle";
}
};
struct Rectangle {
friend std::ostream& operator<<(std::ostream& os, Rectangle) {
return os << "Rectangle";
}
};
using Shape = boost::variant<Circle, Rectangle>;
int main() {
Shape shape = Rectangle();
std::cout << shape << "\n";
shape = Circle();
std::cout << shape << "\n";
}
变体:area(Shape)
实现
#include <boost/variant.hpp>
#include <iostream>
struct Point { double x,y; };
struct Circle {
Point centre;
double radius;
friend std::ostream& operator<<(std::ostream& os, Circle) {
return os << "Circle";
}
};
struct Rectangle {
Point topleft, bottomright;
friend std::ostream& operator<<(std::ostream& os, Rectangle) {
return os << "Rectangle";
}
};
struct area_f : boost::static_visitor<double> {
double operator()(Rectangle const& r) const {
return std::abs(r.bottomright.x - r.topleft.x) *
std::abs(r.bottomright.y - r.topleft.y);
}
double operator()(Circle const& r) const {
return (r.radius*r.radius) * M_PI;
}
};
using Shape = boost::variant<Circle, Rectangle>;
double area(Shape const& s) {
return boost::apply_visitor(area_f(), s);
}
int main() {
Shape shape = Rectangle { { 1,1 }, { 5,5 } };
std::cout << shape << ": " << area(shape) << "\n";
shape = Circle { { 10, 10 }, 5 };
std::cout << shape << ": " << area(shape) << "\n";
}
动态多态性
同样使用你可以在其他语言中使用的多态性:
#include <iostream>
#include <cmath>
struct Point { double x,y; };
struct Shape {
virtual ~Shape() {}
virtual double area() const = 0;
protected:
virtual void print(std::ostream& os) const = 0;
friend std::ostream& operator<<(std::ostream& os, Shape const& s) {
s.print(os);
return os;
}
};
struct Circle : Shape {
Circle(Point c, double r) : centre(c), radius(r) {}
Point centre;
double radius;
virtual double area() const override {
return (radius*radius) * M_PI;
}
virtual ~Circle() { }
protected:
virtual void print(std::ostream& os) const override {
os << "Circle";
}
};
struct Rectangle : Shape {
Rectangle(Point tl, Point br) : topleft(tl), bottomright(br) {}
Point topleft, bottomright;
virtual double area() const override {
return std::abs(bottomright.x - topleft.x) *
std::abs(bottomright.y - topleft.y);
}
virtual ~Rectangle() { }
protected:
virtual void print(std::ostream& os) const override {
os << "Rectangle";
}
};
int main() {
Rectangle r { { 1,1 }, { 5,5 } };
{
Shape const& shape = r;
std::cout << shape << ": " << shape.area() << "\n";
}
Circle c { { 10, 10 }, 5 };
{
Shape const& shape = c;
std::cout << shape << ": " << shape.area() << "\n";
}
}
Shape 是可以包含 Rectangle 或 Circle 的框。如果你有一个矩形并想把它放在一个盒子里,你需要一个实际的物理盒子。你不能只声明这个有某某地址的地方,矩形恰好所在的地方,现在是一个盒子,因为没有盒子。
我有一个 boost::variant
定义如下:
typedef boost::variant<Rectangle, Circle> Shape;
现在我想从 Rectangle
得到一个 Shape
指针:
Rectangle *rectanglePointer = new Rectangle();
Shape *shapePointer = rectanglePointer;
但是没用。我在这里弄错了什么?
简单。变体不是那样工作的。
它们专门用于静态多态性。
您/可以/存储运行时多态引用(或指针),但您仍然需要使用 boost::get<>
或访问者来提取实际值。
在你的例子中,Shape
显然不是 Rectangle
的基础 class,这就是编译器将拒绝静态转换的原因(up-cast 不适用于不相关的类型 Rectangle
和 Shape
).
变体,简单
带有变体的简单示例:
#include <boost/variant.hpp>
#include <iostream>
struct Circle {
friend std::ostream& operator<<(std::ostream& os, Circle) {
return os << "Circle";
}
};
struct Rectangle {
friend std::ostream& operator<<(std::ostream& os, Rectangle) {
return os << "Rectangle";
}
};
using Shape = boost::variant<Circle, Rectangle>;
int main() {
Shape shape = Rectangle();
std::cout << shape << "\n";
shape = Circle();
std::cout << shape << "\n";
}
变体:area(Shape)
实现
#include <boost/variant.hpp>
#include <iostream>
struct Point { double x,y; };
struct Circle {
Point centre;
double radius;
friend std::ostream& operator<<(std::ostream& os, Circle) {
return os << "Circle";
}
};
struct Rectangle {
Point topleft, bottomright;
friend std::ostream& operator<<(std::ostream& os, Rectangle) {
return os << "Rectangle";
}
};
struct area_f : boost::static_visitor<double> {
double operator()(Rectangle const& r) const {
return std::abs(r.bottomright.x - r.topleft.x) *
std::abs(r.bottomright.y - r.topleft.y);
}
double operator()(Circle const& r) const {
return (r.radius*r.radius) * M_PI;
}
};
using Shape = boost::variant<Circle, Rectangle>;
double area(Shape const& s) {
return boost::apply_visitor(area_f(), s);
}
int main() {
Shape shape = Rectangle { { 1,1 }, { 5,5 } };
std::cout << shape << ": " << area(shape) << "\n";
shape = Circle { { 10, 10 }, 5 };
std::cout << shape << ": " << area(shape) << "\n";
}
动态多态性
同样使用你可以在其他语言中使用的多态性:
#include <iostream>
#include <cmath>
struct Point { double x,y; };
struct Shape {
virtual ~Shape() {}
virtual double area() const = 0;
protected:
virtual void print(std::ostream& os) const = 0;
friend std::ostream& operator<<(std::ostream& os, Shape const& s) {
s.print(os);
return os;
}
};
struct Circle : Shape {
Circle(Point c, double r) : centre(c), radius(r) {}
Point centre;
double radius;
virtual double area() const override {
return (radius*radius) * M_PI;
}
virtual ~Circle() { }
protected:
virtual void print(std::ostream& os) const override {
os << "Circle";
}
};
struct Rectangle : Shape {
Rectangle(Point tl, Point br) : topleft(tl), bottomright(br) {}
Point topleft, bottomright;
virtual double area() const override {
return std::abs(bottomright.x - topleft.x) *
std::abs(bottomright.y - topleft.y);
}
virtual ~Rectangle() { }
protected:
virtual void print(std::ostream& os) const override {
os << "Rectangle";
}
};
int main() {
Rectangle r { { 1,1 }, { 5,5 } };
{
Shape const& shape = r;
std::cout << shape << ": " << shape.area() << "\n";
}
Circle c { { 10, 10 }, 5 };
{
Shape const& shape = c;
std::cout << shape << ": " << shape.area() << "\n";
}
}
Shape 是可以包含 Rectangle 或 Circle 的框。如果你有一个矩形并想把它放在一个盒子里,你需要一个实际的物理盒子。你不能只声明这个有某某地址的地方,矩形恰好所在的地方,现在是一个盒子,因为没有盒子。