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 不适用于不相关的类型 RectangleShape).

变体,简单

带有变体的简单示例:

Live On Coliru

#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) 实现

Live On Coliru

#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";

}

动态多态性

同样使用你可以在其他语言中使用的多态性:

Live On Coliru

#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 的框。如果你有一个矩形并想把它放在一个盒子里,你需要一个实际的物理盒子。你不能只声明这个有某某地址的地方,矩形恰好所在的地方,现在是一个盒子,因为没有盒子。